I am setting up very basic code-first approach database context for my application. I've MVC (UI), and Class library (EntityFramework) projects under my solution. On Update-Database getting error Instance failure.
// Migration configuration
internal sealed class Configuration : DbMigrationsConfiguration<UrfPractice.EntityFramework.UrfPracticeDbContext>
{
public Configuration()
{
AutomaticMigrationsEnabled = true;
}
}
// Database context
public class UrfPracticeDbContext : DbContext
{
static UrfPracticeDbContext()
{
Database.SetInitializer<UrfPracticeDbContext>(null);
}
public UrfPracticeDbContext() : base("name=DefaultConnectionString")
{
Configuration.AutoDetectChangesEnabled = true;
Configuration.LazyLoadingEnabled = true;
Configuration.ProxyCreationEnabled = false;
}
public DbSet<Entities.Customer> Customers { get; set; }
}
// Customer migration
public partial class Customer : DbMigration
{
public override void Up()
{
CreateTable(
"dbo.tblCustomers",
c => new {
Id = c.Int(nullable: false, identity: true),
CustomerId = c.Int(nullable: false),
Fullname = c.String(nullable: false, maxLength: 256)
}).PrimaryKey(t => t.Id);
}
public override void Down()
{ DropTable("dbo.tblCustomers"); }
}
// Entity class
[Table("tblCustomers")] public class Customer {
[Key]
public int CustomerId { get; set; }
[MaxLength(250)]
public string Fullname { get; set; }
}
Screenshot=> https://user-images.githubusercontent.com/47334134/53000129-b4582800-3438-11e9-9d17-4f1903c5d623.png
Related
I am trying to test my project using ef 6. here is the situation: I have the mold class and have some generic services like GetAll,GetById,Create,Update, Delete. trying to test these methods using xUnit. Stuck in mocking.
public partial class TblPtsVMold :IMoldObject
{
public int MoldId { get; set; }
public string? MoldType { get; set; }
public string? Plant { get; set; }
}
public partial class PTSProdContext : DbContext
{
private IConfiguration _configuration { get; set; }
public PTSProdContext()
{
}
public PTSProdContext(DbContextOptions<PTSProdContext> options)
: base(options)
{
}
public virtual DbSet<TblPtsVMold> TblPtsVMolds { get; set; } = null!;
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
if (!optionsBuilder.IsConfigured)
{
optionsBuilder.UseSqlServer
(_configuration.GetConnectionString
(_configuration["EnvionmentString:ENVIRONMENT"]));
}
}
}
public class PTSContextFactory
{
public string DbConnectionString { get; set; }
public PTSContextFactory(string dbConnectionString)
{
DbConnectionString = dbConnectionString;
}
public PTSProdContext CreateDbContext()
{
DbContextOptionsBuilder<PTSProdContext> options = new DbContextOptionsBuilder<PTSProdContext>();
options.UseSqlServer(DbConnectionString);
return new PTSProdContext(options.Options);
}
public interface IDataService<T>
{
IEnumerable<T> GetAll();
IEnumerable<T> GetAllWithID(List<int> Ids);
T Get(int id);
T Create(T entity);
}
generic dataservice class
public class GenericDataService<T> : IDataService<T> where T : class, IDomainObject
{
public readonly PTSContextFactory _contextFactory;
public GenericDataService(PTSContextFactory contextFactory)
{
_contextFactory = contextFactory;
}
public GenericDataService()
{
}
public IEnumerable<T> GetAllWithID(List<int> Ids)
{
using (PTSProdContext context = _contextFactory.CreateDbContext())
{
IEnumerable<T> entities = context.Set<T>().Where(e => Ids.Contains(e.Id)).ToList();
if (entities == null)
{
WeakReferenceMessenger.Default.Send(new LookupExceptionMessage(string.Format("Can't find record.")));
return default;
}
return entities;
}
}
public IEnumerable<T> GetAll()
{
using (PTSProdContext context = _contextFactory.CreateDbContext())
{
IEnumerable<T> results = context.Set<T>().ToList();
if (results == null)
{
return default;
}
return results;
}
}
Test:
[Fact]
public void GetAll_TestClassObjectPassed_ProperMethodCalled()
{
// Arrange
var testObject = new TblPtsVMold() { Id = 1 };
var testList = new List<TblPtsVMold>() { testObject };
var data = new List<TblPtsVMold>
{
new TblPtsVMold { MoldType = "test",Plant="testpass1" },
new TblPtsVMold { MoldType = "ZZZ",Plant="testpass2" },
new TblPtsVMold { MoldType = "AAA",Plant="testpass3" },
}.AsQueryable();
var dbSetMock = new Mock<DbSet<TblPtsVMold>>();
dbSetMock.As<IQueryable<TblPtsVMold>>().Setup(x => x.Provider).Returns(testList.AsQueryable().Provider);
dbSetMock.As<IQueryable<TblPtsVMold>>().Setup(x => x.Expression).Returns(testList.AsQueryable().Expression);
dbSetMock.As<IQueryable<TblPtsVMold>>().Setup(x => x.ElementType).Returns(testList.AsQueryable().ElementType);
dbSetMock.As<IQueryable<TblPtsVMold>>().Setup(x => x.GetEnumerator()).Returns(testList.AsQueryab`your text`le().GetEnumerator());
var context = new Mock<PTSProdContext>();
context.Setup(x => x.Set<TblPtsVMold>()).Returns(dbSetMock.Object);
// Act
var context = new Mock<PTSContextFactory>();
context.Setup(x => x.DbConnectionString).Returns(string.Empty);
var service = new GenericDataService<TblPtsVMold>(context.Object);
var result = service.GetAll();
// Assert
Assert.Equal(testList, result.ToList());
}
context.Setup(x => x.DbConnectionString).Returns(string.Empty); is not correct.
getting error:pportedException : Unsupported expression: x => x.DbConnectionString Non-overridable members (here: PTSContextFactory.get_DbConnectionString) may not be used in setup verification expressions.
How to test GetAll or create method. Is anything wrong here?
Entity Framework classes:
namespace ORM
{
public class Car
{
public int Id { get; set; }
public string Name { get; set; }
public int Price { get; set; }
public virtual List<Wheel> Wheels { get; set; }
}
public class Wheel
{
public int Id { get; set; }
public double Size { get; set; }
public virtual Car Car { get; set; }
}
}
namespace DAL.Entities
{
public class Car
{
public int Id { get; set; }
public string Name { get; set; }
public int Price { get; set; }
public List<Wheel> Wheels { get; set; }
}
public class Wheel
{
public int Id { get; set; }
public double Size { get; set; }
public Car Car { get; set; }
}
}
ORM and DAL models.
Automapper configuration is:
public class DalProfile : Profile
{
public DalProfile()
{
CreateMap<Wheel, Entities.Wheel>()
.ForMember(m => m.Car, opt => opt.Ignore());
CreateMap<Entities.Wheel, Wheel>()
.ForMember(m => m.Car, opt => opt.Ignore());
CreateMap<Car, Entities.Car>()
.AfterMap((src, dest) =>
{
foreach (var wheel in dest.Wheels)
{
wheel.Car = dest;
}
});
CreateMap<Entities.Car, Car>()
.AfterMap((src, dest) =>
{
foreach (var wheel in dest.Wheels)
{
wheel.Car = dest;
}
});
CreateMap<Wheel, Wheel>()
.ForMember(m => m.Car, opt => opt.Ignore());
CreateMap<Car, Car>()
.AfterMap((src, dest) =>
{
foreach (var wheel in dest.Wheels)
{
wheel.Car = dest;
}
});
}
}
Repository class:
public class CarRepository
{
private readonly DbContext context;
public CarRepository(DbContext context)
{
this.context = context;
}
public void Update<T>(int id, T newCar) where T : class
{
var entity = context.Set<T>().Find(id);
Mapper.Map(newCar, entity);
context.SaveChanges();
}
}
Main entry:
static void Main(string[] args)
{
Mapper.Initialize(cfg => cfg.AddProfile(new DalProfile()));
DataContext context = new DataContext();
CarRepository carRepository = new CarRepository(context);
Car car = carRepository.Get(120);
DAL.Entities.Car dalCar = Mapper.Map<Car, DAL.Entities.Car(car);
dalCar.Name = "ew";
dalCar.Wheels[0].Size = 1994;
Car ormCar = Mapper.Map<DAL.Entities.Car, Car>(dalCar);
carRepository.Update(ormCar.Id, ormCar);
}
In my project i have ORM, DAL layers. Inside Update method i want to update only changed values. Of course if do changes with ORM.Car directly like this:
public void Update<T>(ORM.Car car) where T : class
{
var entity = context.Set<Car>().Find(car.id);
entity.Name = "New name";
entity.Wheels[0].Size = 1111;
context.SaveChanges();
}
This works great. Entity framework can update only Name property and related Wheel object.
But in my project i have different layers. So i want to change some properties of DAL.Car than map this object to ORM.Car with Automapper and apply changes like i did with ORM.Car above. But after mapping with Automapper i can't do this cause of Automapper creates new objects after mapping and Entity Framework can't update only needed properties like with ORM.Car directly cause of Dynamic Proxies maybe or i don't know. I want generic Update which looks something like this:
public void Update<T>(int id, T newCar) where T : class
{
var entity = context.Set<T>().Find(id);
Mapper.Map(newCar, entity);
context.SaveChanges();
}
Where newCar is a Car which is converted from DAL.Car;
Can i do this?
I am in the process of Downgrading from EF7 to EF6 due to business decisions. I have looked at several examples but cannot seem to get it to work.
Here is what I have for EF 7
Context:
public class OwnerContext : DbContext
{
protected override void OnConfiguring(DbContextOptionsBuilder options)
{
options.UseSqlServer(#"Server=server\testdbs;Database=test;Trusted_Connection=True;");
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Owner>(entity =>
{
entity.ToTable("Owner");
entity.Property(e => e.Id)
.HasMaxLength(50)
.HasColumnType("varchar");
});
}
public virtual DbSet<Owner> Owner { get; set; }
}
Owner Model
public class Owner
{
public int OwnerId { get; set; }
public string Name { get; set; }
public int Age { get; set; }
}
How I use it
static void Main(string[] args)
{
using (var context = new OwnerContext())
{
var owner = new Owner
{
Name = "First Name",
Age = 4
};
context.Owner.Add(owner);
context.SaveChanges();
Console.ReadLine();
}
}
I got this to work with no issues and I get records in the data base. For EF 6 it is a little different
Here is what I have for EF6
Context
public class OwnerContext : DbContext
{
public OwnerContext(string connectionString) : base(connectionString) { }
public OwnerContext()
: this("OwnerConn")
{
}
public virtual DbSet<Owner> Owner{ get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
var owner = modelBuilder.Entity<Owner>().ToTable("Owner");
owner.Property(e => e.OwnerId)
.HasMaxLength(50)
.HasColumnType("varchar");
owner.HasKey(u => u.OwnerId);
}
}
Model
public class Owner
{
public int OwnerId { get; set; }
public string Name { get; set; }
public int Age { get; set; }
}
How I use it
static void Main(string[] args)
{
try
{
using (var context = new OwnerContext())
{
var person = new Owner
{
Name = "Test Name",
Age = 5
};
context.Owner.Add(person);
context.Entry(person).State = EntityState.Added;
context.SaveChanges();
}
}
catch (Exception exception)
{
Console.WriteLine(exception.Message);
}
Console.ReadLine();
}
ConnectionString
<connectionStrings>
<add name="OwnerConn" connectionString="Server=server\testdbs;Database=test;Trusted_Connection=True;" providerName="System.Data.SqlClient" />
</connectionStrings>
It seems to be very simple based on the tutorials. Hoever, I cant seem to get the changes to be reflected in the database. However, when I restart the console app and pull the records like this.
var rows = from a in context.Owner select a
It returns rows but I still don't see them in the DB. I'm out of ideas so hopefully someone can help.
In my mvc application i have a base model as below
namespace ModulericaV1.Models
{
public class BaseModel
{
private ApplicationDbContext db = new ApplicationDbContext();
public DateTime? CrDate { get; set; }
[ForeignKey("CrUser")]
public ApplicationUser UserCr { get; set; }
public string CrUser { get; set; }
public DateTime? MdDate { get; set; }
[ForeignKey("MdUser")]
public ApplicationUser UserMd { get; set; }
public string MdUser { get; set; }
public bool IsDeleted { get; set; }
public ApplicationUser GetUserObject(string id)
{
var UserObject = db.Users.Find(id);
return UserObject;
}
public void LogBasic()
{
if (this.CrDate == null)
{
this.CrDate = System.DateTime.Now;
this.CrUser = HttpContext.Current.User.Identity.GetUserId();
}
else
{
this.MdDate = System.DateTime.Now;
this.MdUser = HttpContext.Current.User.Identity.GetUserId();
}
}
}
}
All my models inherits the :BaseModel. What i am trying to do, calling LogBasic() method for all Create and Update DB queries so i can log which user create new row or made changes.
Where is the place should i need to call LogBasic() method .
Probably something like this should work:
public class ApplicationDbContext : DbContext {
// ...
public override int SaveChanges () {
if(HasChanges()){
foreach(var entry in Entries<BaseModel>()){
((BaseModel)entry.Entity).LogBasic();
}
}
}
// ...
}
The best place to do this is in the ApplicationDbContext on the SaveChanges() method. You can iterate through all of the items that are pending updates and then if they are of a BaseModel, log them.
I don't have the exact syntax to hand, but this is the idea:
public class ApplicationDbContext : DbContext
{
//.....
public override int SaveChanges()
{
foreach(var entity in this.ChangeTracker.Entries)
{
var baseModel = entity as BaseModel;
if(baseModel!=null)
{
switch(entity.State)
{
case State.Modified;
// Do things with an updated version
case State.Deleted:
// Do things with the deleted version
case State.Added:
{
// Do things with the Added entity
baseModel.LogBasic();
break;
}
}
}
base.SaveChanges();
}
}
I'm trying out Entity Framework Code first CTP4. Suppose I have:
public class Parent
{
public int Id { get; set; }
public string Name { get; set; }
}
public class Child
{
public int Id { get; set; }
public string Name { get; set; }
public Parent Mother { get; set; }
}
public class TestContext : DbContext
{
public DbSet<Parent> Parents { get; set; }
public DbSet<Child> Children { get; set; }
}
public class ChildEdit
{
public int Id { get; set; }
public string Name { get; set; }
public int MotherId { get; set; }
}
Mapper.CreateMap<Child, ChildEdit>();
Mapping to the Edit model is not a problem. On my screen I select the mother through some control (dropdownlist, autocompleter, etc) and the Id of the mother gets posted in back:
[HttpPost]
public ActionResult Edit(ChildEdit posted)
{
var repo = new TestContext();
var mapped = Mapper.Map<ChildEdit, Child>(posted); // <------- ???????
}
How should I solve the last mapping? I don't want to put Mother_Id in the Child object. For now I use this solution, but I hope it can be solved in Automapper.
Mapper.CreateMap<ChildEdit, Child>()
.ForMember(i => i.Mother, opt => opt.Ignore());
var mapped = Mapper.Map<ChildEdit, Child>(posted);
mapped.Mother = repo.Parents.Find(posted.MotherId);
EDIT
This works, but now I have to do that for each foreign key (BTW: context would be injected in final solution):
Mapper.CreateMap<ChildEdit, Child>();
.ForMember(i => i.Mother,
opt => opt.MapFrom(o =>
new TestContext().Parents.Find(o.MotherId)
)
);
What I'd really like would be:
Mapper.CreateMap<int, Parent>()
.ForMember(i => i,
opt => opt.MapFrom(o => new TestContext().Parents.Find(o))
);
Mapper.CreateMap<ChildEdit, Child>();
Is that possible with Automapper?
First, I'll assume that you have a repository interface like IRepository<T>
Afterwards create the following class:
public class EntityConverter<T> : ITypeConverter<int, T>
{
private readonly IRepository<T> _repository;
public EntityConverter(IRepository<T> repository)
{
_repository = repository;
}
public T Convert(ResolutionContext context)
{
return _repository.Find(System.Convert.ToInt32(context.SourceValue));
}
}
Basically this class will be used to do all the conversion between an int and a domain entity. It uses the "Id" of the entity to load it from the Repository. The IRepository will be injected into the converter using an IoC container, but more and that later.
Let's configure the AutoMapper mapping using:
Mapper.CreateMap<int, Mother>().ConvertUsing<EntityConverter<Mother>>();
I suggest creating this "generic" mapping instead so that if you have other references to "Mother" on other classes they're mapped automatically without extra-effort.
Regarding the Dependency Injection for the IRepository, if you're using Castle Windsor, the AutoMapper configuration should also have:
IWindsorContainer container = CreateContainer();
Mapper.Initialize(map => map.ConstructServicesUsing(container.Resolve));
I've used this approach and it works quite well.
Here's how I did it: (using ValueInjecter)
I made the requirements a little bigger just to show how it works
[TestFixture]
public class JohnLandheer
{
[Test]
public void Test()
{
var child = new Child
{
Id = 1,
Name = "John",
Mother = new Parent { Id = 3 },
Father = new Parent { Id = 9 },
Brother = new Child { Id = 5 },
Sister = new Child { Id = 7 }
};
var childEdit = new ChildEdit();
childEdit.InjectFrom(child)
.InjectFrom<EntityToInt>(child);
Assert.AreEqual(1, childEdit.Id);
Assert.AreEqual("John", childEdit.Name);
Assert.AreEqual(3, childEdit.MotherId);
Assert.AreEqual(9, childEdit.FatherId);
Assert.AreEqual(5, childEdit.BrotherId);
Assert.AreEqual(7, childEdit.SisterId);
Assert.AreEqual(0, childEdit.Sister2Id);
var c = new Child();
c.InjectFrom(childEdit)
.InjectFrom<IntToEntity>(childEdit);
Assert.AreEqual(1, c.Id);
Assert.AreEqual("John", c.Name);
Assert.AreEqual(3, c.Mother.Id);
Assert.AreEqual(9, c.Father.Id);
Assert.AreEqual(5, c.Brother.Id);
Assert.AreEqual(7, c.Sister.Id);
Assert.AreEqual(null, c.Sister2);
}
public class Entity
{
public int Id { get; set; }
}
public class Parent : Entity
{
public string Name { get; set; }
}
public class Child : Entity
{
public string Name { get; set; }
public Parent Mother { get; set; }
public Parent Father { get; set; }
public Child Brother { get; set; }
public Child Sister { get; set; }
public Child Sister2 { get; set; }
}
public class ChildEdit
{
public int Id { get; set; }
public string Name { get; set; }
public int MotherId { get; set; }
public int FatherId { get; set; }
public int BrotherId { get; set; }
public int SisterId { get; set; }
public int Sister2Id { get; set; }
}
public class EntityToInt : LoopValueInjection
{
protected override bool TypesMatch(Type sourceType, Type targetType)
{
return sourceType.IsSubclassOf(typeof(Entity)) && targetType == typeof(int);
}
protected override string TargetPropName(string sourcePropName)
{
return sourcePropName + "Id";
}
protected override bool AllowSetValue(object value)
{
return value != null;
}
protected override object SetValue(object sourcePropertyValue)
{
return (sourcePropertyValue as Entity).Id;
}
}
public class IntToEntity : LoopValueInjection
{
protected override bool TypesMatch(Type sourceType, Type targetType)
{
return sourceType == typeof(int) && targetType.IsSubclassOf(typeof(Entity));
}
protected override string TargetPropName(string sourcePropName)
{
return sourcePropName.RemoveSuffix("Id");
}
protected override bool AllowSetValue(object value)
{
return (int)value > 0;
}
protected override object SetValue(object sourcePropertyValue)
{
// you could as well do repoType = IoC.Resolve(typeof(IRepo<>).MakeGenericType(TargetPropType))
var repoType = typeof (Repo<>).MakeGenericType(TargetPropType);
var repo = Activator.CreateInstance(repoType);
return repoType.GetMethod("Get").Invoke(repo, new[] {sourcePropertyValue});
}
}
class Repo<T> : IRepo<T> where T : Entity, new()
{
public T Get(int id)
{
return new T{Id = id};
}
}
private interface IRepo<T>
{
T Get(int id);
}
}
It's possible to define the foreign key in EF this way as well:
[ForeignKey("MotherId")]
public virtual Parent Mother { get; set; }
public int MotherId { get; set; }
In this case, It's not necessary to do an extra query to find the Mother. Just Assign the ViewModel's MotherId to the Model's MotherId.