"Object reference not set to an instance of an object." exception while migration with Entity Framework Core 6 by OwnsMany with EntityTypeBuilder - entity-framework-core

I get a NullReferenceException while migrating my model with EF Core 6.
Here is the error message:
System.NullReferenceException: Object reference not set to an instance of an object.
at Microsoft.EntityFrameworkCore.Metadata.Conventions.Internal.ConventionBatchExtensions.Run(IConventionBatch batch, InternalForeignKeyBuilder relationshipBuilder)
at Microsoft.EntityFrameworkCore.Metadata.Internal.InternalForeignKeyBuilder.ReuniquifyImplicitProperties(Boolean force)
at Microsoft.EntityFrameworkCore.Metadata.Conventions.ForeignKeyPropertyDiscoveryConvention.DiscoverProperties(IConventionForeignKeyBuilder relationshipBuilder, IConventionContext context)
at Microsoft.EntityFrameworkCore.Metadata.Conventions.ForeignKeyPropertyDiscoveryConvention.ProcessForeignKeyRequirednessChanged(IConventionForeignKeyBuilder relationshipBuilder, IConventionContext`1 context)
at Microsoft.EntityFrameworkCore.Metadata.Conventions.Internal.ConventionDispatcher.ImmediateConventionScope.OnForeignKeyRequirednessChanged(IConventionForeignKeyBuilder relationshipBuilder)
at Microsoft.EntityFrameworkCore.Metadata.Conventions.Internal.ConventionDispatcher.OnForeignKeyRequirednessChangedNode.Run(ConventionDispatcher dispatcher)
at Microsoft.EntityFrameworkCore.Metadata.Conventions.Internal.ConventionDispatcher.DelayedConventionScope.Run(ConventionDispatcher dispatcher)
at Microsoft.EntityFrameworkCore.Metadata.Conventions.Internal.ConventionDispatcher.ConventionBatch.Run()
at Microsoft.EntityFrameworkCore.Metadata.Conventions.Internal.ConventionDispatcher.ConventionBatch.Run(IConventionForeignKey foreignKey)
at Microsoft.EntityFrameworkCore.Metadata.Builders.EntityTypeBuilder`1.OwnsManyBuilder[TRelatedEntity](TypeIdentity ownedType, MemberIdentity navigation)
at Microsoft.EntityFrameworkCore.Metadata.Builders.EntityTypeBuilder`1.OwnsMany[TRelatedEntity](String navigationName, Action`1 buildAction)
at Analyzing.Modules.Project.Persistence.Records.RecordConfiguration.Configure(EntityTypeBuilder`1 builder) in C:\Repo\...\Analyzing.Modules.Project.Persistence\Records\RecordConfiguration.cs:line 27
This is my Configuration class:
public class RecordConfiguration : IEntityTypeConfiguration<Record>
{
public void Configure(EntityTypeBuilder<Record> builder)
{
builder.ToTable("Recordings");
builder.HasKey(x => x.Id);
builder.Property(x => x.Id)
.HasConversion(v => v.Value,
v => new RecordId(v));
builder.Property(x => x.Name);
builder.Property(x => x.Task);
builder.OwnsMany<SensorId>("Sensors", z => {
z.ToTable("Sensors");
z.WithOwner().HasForeignKey("Id");
z.Property(_ => _.Value);
});
}
}
And my SensorId class
public class SensorId : TypedIdValueBase
{
public SensorId(string value) : base(value)
{
}
}
public abstract class TypedIdValueBase : IEquatable<TypedIdValueBase>
{
public string Value { get; }
protected TypedIdValueBase(string value)
{
if (string.IsNullOrEmpty(value))
{
throw new InvalidOperationException("Id value cannot be empty!");
}
Value = value;
}
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj))
{
return false;
}
return obj is TypedIdValueBase other && Equals(other);
}
public override int GetHashCode()
{
return Value.GetHashCode();
}
public bool Equals(TypedIdValueBase other)
{
return this.Value.ToLower() == other?.Value.ToLower();
}
public static bool operator ==(TypedIdValueBase obj1, TypedIdValueBase obj2)
{
if (object.Equals(obj1, null))
{
if (object.Equals(obj2, null))
{
return true;
}
return false;
}
return obj1.Equals(obj2);
}
public static bool operator !=(TypedIdValueBase x, TypedIdValueBase y)
{
return !(x == y);
}
}
My model class:
public class Record : AuditableEntity, IAggregateRoot
{
private readonly List<SensorId> _sensors = new();
private Record() { }
private Record(string id, string name, string task)
{
Id = new RecordId(id);
Name = name;
Task = task;
}
public static Result<Record> Create(string id, string name, string task)
{
if (string.IsNullOrEmpty(id))
throw new ArgumentNullException(nameof(id));
if (string.IsNullOrEmpty(name))
throw new ArgumentNullException(nameof(name));
var record = new Record(id, name, task);
return Result.Ok(record);
}
public string Name { get; }
public RecordId Id { get; }
public string Task { get; }
public IReadOnlyList<SensorId> Sensors => _sensors;
public void AddSensorId(SensorId sensorId)
{
_sensors.Add(sensorId);
}
}
It is Entity Framework Core 6 with the SQLite provider. The DbContext is creating while runtime with DesignTimeDbContextFactory.
If I ignore the property Sensors, the migrations finishes successfully.
I don't know where the error comes from. Do you have any idea?
A solution form a another post proposes to delete the snapshot file. This did not solve the problem.
A successful migration including the property Sensors would be nice.

Related

How do I setup a list of test organizations with my new DBContext?

I have an application with uses multiple contexts for EF, some are code first, some server first, and all are dynamic.
I have a class that I call to get these contexts in my app.
Each context implements an interface such as:
public interface IDatabaseContextSwitcher
{
IVGSContext GetDatabase(string organization);
IVGSContext GetDatabase(Guid organizationGuid, string email);
IVGSServerConn GetServerDatabase(string databaseName);
IAuthContext GetAuthorizationDatabase();
}
I therefore has a class that implments the instances of these interfaces in the application. (VGSContext, VGSServerConn, and AuthContext).
I am trying to test these in my test project. I have made new classes from the interfaces with the plan to plug in some DbSets into these new classes and then test that my controllers do the correct thing.
However, I can't seem to figure out how to initialize the DBSets.
For example the following dies on Add:
public AuthContextForTesting()
{
Organizations.Add(new Organization()
{OrganizationName = "Test1", PK_Organization = Guid.Parse("34CE4F83-B3C9-421B-B1F3-42BBCDA9A004")});
var cnt = Organizations.Count();
}
public DbSet<Organization> Organizations { get; set; }
I tried to initialize the DBSet with:
Organizations=new DbSet();
But it gives an error that this is not allowed due to permissions.
How do I set up my initial dbsets in code for my tests?
To be able to do this, you first have to derive a class from DBSet. Sadly, my app uses both Core EF and EF 6 so I had to create 2 classes.
EF 6 Class
public class FakeDbSet<T> : System.Data.Entity.DbSet<T>, IDbSet<T> where T : class
{
List<T> _data;
public FakeDbSet()
{
_data = new List<T>();
}
public override T Find(params object[] keyValues)
{
throw new NotImplementedException("Derive from FakeDbSet<T> and override Find");
}
public override T Add(T item)
{
_data.Add(item);
return item;
}
public override T Remove(T item)
{
_data.Remove(item);
return item;
}
public override T Attach(T item)
{
return null;
}
public T Detach(T item)
{
_data.Remove(item);
return item;
}
public override T Create()
{
return Activator.CreateInstance<T>();
}
public TDerivedEntity Create<TDerivedEntity>() where TDerivedEntity : class, T
{
return Activator.CreateInstance<TDerivedEntity>();
}
public List<T> Local
{
get { return _data; }
}
public override IEnumerable<T> AddRange(IEnumerable<T> entities)
{
_data.AddRange(entities);
return _data;
}
public override IEnumerable<T> RemoveRange(IEnumerable<T> entities)
{
for (int i = entities.Count() - 1; i >= 0; i--)
{
T entity = entities.ElementAt(i);
if (_data.Contains(entity))
{
Remove(entity);
}
}
return this;
}
Type IQueryable.ElementType
{
get { return _data.AsQueryable().ElementType; }
}
System.Linq.Expressions.Expression IQueryable.Expression
{
get { return _data.AsQueryable().Expression; }
}
IQueryProvider IQueryable.Provider
{
get { return _data.AsQueryable().Provider; }
}
IEnumerator IEnumerable.GetEnumerator()
{
return _data.GetEnumerator();
}
IEnumerator<T> IEnumerable<T>.GetEnumerator()
{
return _data.GetEnumerator();
}
}
The EF Core had to include some interfaces to work.
public class FakeCoreDbSet<T> : Microsoft.EntityFrameworkCore.DbSet<T> , IQueryable, IEnumerable<T> where T : class
{
List<T> _data;
public FakeCoreDbSet()
{
_data = new List<T>();
}
public override T Find(params object[] keyValues)
{
throw new NotImplementedException("Derive from FakeDbSet<T> and override Find");
}
public override EntityEntry<T> Add(T item)
{
_data.Add(item);
//return item;
return null;
}
public override EntityEntry<T> Remove(T item)
{
_data.Remove(item);
//return item;
return null;
}
public override EntityEntry<T> Attach(T item)
{
return null;
}
public T Detach(T item)
{
_data.Remove(item);
return item;
}
public IList GetList()
{
return _data.ToList();
}
//public override T Create()
//{
// return Activator.CreateInstance<T>();
//}
public TDerivedEntity Create<TDerivedEntity>() where TDerivedEntity : class, T
{
return Activator.CreateInstance<TDerivedEntity>();
}
public List<T> Local
{
get { return _data; }
}
public override void AddRange(IEnumerable<T> entities)
{
_data.AddRange(entities);
//return _data;
}
public override void RemoveRange(IEnumerable<T> entities)
{
for (int i = entities.Count() - 1; i >= 0; i--)
{
T entity = entities.ElementAt(i);
if (_data.Contains(entity))
{
Remove(entity);
}
}
// this;
}
Type IQueryable.ElementType
{
get { return _data.AsQueryable().ElementType; }
}
System.Linq.Expressions.Expression IQueryable.Expression
{
get { return _data.AsQueryable().Expression; }
}
IQueryProvider IQueryable.Provider
{
get { return _data.AsQueryable().Provider; }
}
IEnumerator IEnumerable.GetEnumerator()
{
return _data.GetEnumerator();
}
IEnumerator<T> IEnumerable<T>.GetEnumerator()
{
return _data.GetEnumerator();
}
}
Once these were created I could use MockObjects to get to them.
Note _dbContextSwitcher is the class created with a Moq that calls the different databases.
var vgsdatabase = new Mock<IVGSContext>();
var settings=new FakeCoreDbSet<Setting>();
settings.Add(new Setting()
{
SettingID = "OrgPrivacy",
PK_Setting = Guid.NewGuid(),
UserID = "",
Value = "No"
});
vgsdatabase.Setup(s => s.Setting).Returns(settings);
_dbcontextSwitcher.Setup(s => s.GetDatabase(It.IsAny<string>())).Returns(vgsdatabase.Object);

Unit testing generic repository

I'm pretty new to unit testing and I'm having some problems with regards, to unit testing a generic repository in my application. I've implemented the unit of work pattern in my ASP.NET MVC application. My classes look like this:
public class UnitOfWork : IUnitOfWork
{
private bool disposed = false;
private IGenericRepository<Shop> _shopRespository;
public UnitOfWork(PosContext context)
{
this.Context = context;
}
public PosContext Context { get; private set; }
public IGenericRepository<Shop> ShopRepository
{
get
{
return this._shopRespository ?? (this._shopRespository = new GenericRepository<Shop>(this.Context));
}
}
public void SaveChanges()
{
this.Context.SaveChanges();
}
public void Dispose()
{
this.Dispose(true);
}
protected virtual void Dispose(bool disposing)
{
if (!this.disposed)
{
if (disposing)
{
this.Context.Dispose();
}
this.disposed = true;
}
}
}
public class PosContext : DbContext, IPosContext
{
public DbSet<Shop> Shops { get; private set; }
}
public class GenericRepository<T> : IGenericRepository<T>
where T : class
{
private readonly PosContext context;
private readonly DbSet<T> dbSet;
public GenericRepository(PosContext context)
{
this.context = context;
this.dbSet = context.Set<T>();
}
public virtual IEnumerable<T> Get(
Expression<Func<T, bool>> filter = null,
Func<IQueryable<T>, IOrderedQueryable<T>> orderBy = null,
string includeProperties = "")
{
IQueryable<T> query = this.dbSet;
if (filter != null)
{
query = query.Where(filter);
}
foreach (var includeProperty in includeProperties.Split
(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries))
{
query = query.Include(includeProperty);
}
if (orderBy != null)
{
return orderBy(query).ToList();
}
else
{
return query.ToList();
}
}
public virtual T Find(object id)
{
return this.dbSet.Find(id);
}
public virtual void Add(T entity)
{
this.dbSet.Add(entity);
}
public virtual void Remove(object id)
{
T entityToDelete = this.dbSet.Find(id);
this.Remove(entityToDelete);
}
public virtual void Remove(T entityToDelete)
{
if (this.context.Entry(entityToDelete).State == EntityState.Detached)
{
this.dbSet.Attach(entityToDelete);
}
this.dbSet.Remove(entityToDelete);
}
public virtual void Update(T entityToUpdate)
{
this.dbSet.Attach(entityToUpdate);
this.context.Entry(entityToUpdate).State = EntityState.Modified;
}
I'm using NUnit and FakeItEasy to write my unit tests. In my set up function, I create a UnitIfWork object with a fake PosContext object. I then populate the context with a few Shop objects.
[SetUp]
public void SetUp()
{
this.unitOfWork = new UnitOfWork(A.Fake<PosContext>());
this.unitOfWork.ShopRepository.Add(new Shop() { Id = 1, Name = "Test name1" });
this.unitOfWork.ShopRepository.Add(new Shop() { Id = 2, Name = "Test name2" });
this.unitOfWork.ShopRepository.Add(new Shop() { Id = 3, Name = "Test name3" });
this.unitOfWork.ShopRepository.Add(new Shop() { Id = 4, Name = "Test name4" });
this.unitOfWork.ShopRepository.Add(new Shop() { Id = 5, Name = "Test name5" });
this.Controller = new ShopController(this.unitOfWork);
}
It works fine when I test the Find-method of the GenericRepository. The correct Shop object is returned and I can assert that it works fine:
[TestCase]
public void DetailsReturnsCorrectShop()
{
// Arrange
int testId = 1;
// Act
Shop shop = this.unitOfWork.ShopRepository.Find(testId);
ViewResult result = this.Controller.Details(testId) as ViewResult;
// Assert
Shop returnedShop = (Shop)result.Model;
Assert.AreEqual(testId, returnedShop.Id);
}
But when I want to test that the Get-method returns all shops from the repository, if I do not give any filter params, I get an empty list back. I can't figure out why?
[TestCase]
public void IndexReturnsListOfShops()
{
// Arrange
// Act
ViewResult result = this.Controller.Index() as ViewResult;
// Assert
List<Shop> returnedShops = (List<Shop>)result.Model;
Assert.AreEqual(5, returnedShops.Count);
}
The ShopController looks like this:
public class ShopController : Controller
{
private readonly IUnitOfWork unitOfWork;
public ShopController(IUnitOfWork unitOfWork)
{
this.unitOfWork = unitOfWork;
}
// GET: /Shop/
public ActionResult Index()
{
return View(this.unitOfWork.ShopRepository.Get());
}
// GET: /Shop/Details/5
public ActionResult Details(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
Shop shop = this.unitOfWork.ShopRepository.Find(id);
if (shop == null)
{
return HttpNotFound();
}
return View(shop);
}
}
Can you help me figure out why I get an empty list back from the Get-method?

Instance in Caliburn Micro

We are using Caliburn Micro for the first time.
We have a AppBootstrapper inherited from ShellViewModel.
Situvation is that VieModels should have the same instance unless it is reset.
we are able to achieve shared or not shared everytime, but releasing the export whenever needed is still a mystery.
public class AppBootstrapper : Bootstrapper<ShellViewModel>
{
private static CompositionContainer _container;
protected override void Configure()
{
try
{
_container = new CompositionContainer(
new AggregateCatalog(AssemblySource.Instance.Select(x => new AssemblyCatalog(x))));
var batch = new CompositionBatch();
batch.AddExportedValue<IWindowManager>(new WindowManager());
batch.AddExportedValue<IEventAggregator>(new EventAggregator());
batch.AddExportedValue(_container);
StyleManager.ApplicationTheme = ThemeManager.FromName("Summer");
_container.Compose(batch);
}
catch (Exception exception)
{
}
}
public static void ReleaseAll()
{
}
protected override object GetInstance(Type serviceType, string key)
{
try
{
var contract = string.IsNullOrEmpty(key) ? AttributedModelServices.GetContractName(serviceType) : key;
var exports = _container.GetExportedValues<object>(contract);
if (exports.Any())
return exports.First();
throw new Exception(string.Format("Could not locate any instances of contract {0}.", contract));
}
catch (ReflectionTypeLoadException ex)
{
foreach (Exception inner in ex.LoaderExceptions)
{
// write details of "inner", in particular inner.Message
}
return null;
}
}
protected override IEnumerable<object> GetAllInstances(Type serviceType)
{
try
{
return _container.GetExportedValues<object>(AttributedModelServices.GetContractName(serviceType));
}
catch (Exception exception)
{
return null;
}
}
protected override void BuildUp(object instance)
{
_container.SatisfyImportsOnce(instance);
}
}
ShellViewModel
[Export(typeof(ShellViewModel))]
public sealed class ShellViewModel : Conductor<IScreen>.Collection.OneActive, IHandle<object>
{
[ImportingConstructor]
public ShellViewModel(CompositionContainer compositionContainer, IEventAggregator eventAggregator)
{
CompositionContainer = compositionContainer;
EventAggregator = eventAggregator;
eventAggregator.Subscribe(this);
Items.Add(compositionContainer.GetExportedValue<AViewModel>());
Items.Add(compositionContainer.GetExportedValue<BViewModel>());
ActivateItem(Items.Single(p => p.DisplayName == AppMessageType.A.ToString()));
}
public IEventAggregator EventAggregator { get; set; }
public CompositionContainer CompositionContainer { get; set; }
public void Handle(object message)
{
//throw new System.NotImplementedException();
}
public void B()
{
ActivateItem(Items.Single(p => p.DisplayName == AppMessageType.B.ToString()));
}
public void A()
{
ActivateItem(Items.Single(p => p.DisplayName == AppMessageType.A.ToString()));
}
public void RESET()
{
AppBootstrapper.ReleaseAll();
ActivateItem(Items.Single(p => p.DisplayName == AppMessageType.A.ToString()));
}
public enum AppMessageType
{
A,
B
}
}
AViewModel
[Export(typeof(AViewModel))]
public sealed class AViewModel : Conductor<IScreen>.Collection.OneActive, IHandle<object>
{
[ImportingConstructor]
public AViewModel(CompositionContainer compositionContainer, IEventAggregator eventAggregator)
{
DisplayName = ShellViewModel.AppMessageType.A.ToString();
CompositionContainer = compositionContainer;
EventAggregator = eventAggregator;
eventAggregator.Subscribe(this);
}
public IEventAggregator EventAggregator { get; set; }
public CompositionContainer CompositionContainer { get; set; }
public void Handle(object message)
{
//throw new System.NotImplementedException();
}
}
BViewModel
[Export(typeof(BViewModel))]
public sealed class BViewModel : Conductor<IScreen>.Collection.OneActive, IHandle<object>
{
[ImportingConstructor]
public BViewModel(CompositionContainer compositionContainer, IEventAggregator eventAggregator)
{
DisplayName = ShellViewModel.AppMessageType.B.ToString();
CompositionContainer = compositionContainer;
EventAggregator = eventAggregator;
eventAggregator.Subscribe(this);
}
public IEventAggregator EventAggregator { get; set; }
public CompositionContainer CompositionContainer { get; set; }
public void Handle(object message)
{
//throw new System.NotImplementedException();
}
}
Now AViewModel and BViewModel have single instance.
Whenever Release Button is clicked i want to have new instance of AViewModel and BViewModel.
Hoping to get a reply soon.
Regards,
Vivek
When working with an IoC container, the only part of your code that should take it as a dependency should be your composition root (i.e. your AppBootstrapper in this case). You shouldn't be injecting or referencing the container anywhere else in your code (except possibly factories).
If you want your ShellViewModel to control the lifetime of your child view models (A and B), then you should consider injecting view model factories into your ShellViewModel (via constructor injection if they are required dependencies).
Your AViewModelFactory would just have a single Create method that returns a new instance of AViewModel, likewise with the BViewModelFactory. You can simply new up your view models directly in the factories. If your view models have large dependency chains themselves, then you could consider adding a reference to your container in the factories, although preferably consider looking into the MEF ExportFactory<T> type.

how to pass IDbContext into DbMigrationsConfiguration

Have been implementing Generic Repository, Unit of Work pattern with EF5 Code First from a number of resources and have come up with the following assemblies.
Interfaces, Contexts, Model, Repositories, UnitsOfWork
In the Context assembly I have my migrations folder which contains Configuration.cs
internal sealed class Configuration : DbMigrationsConfiguration<Context.SportsContext>
{
public Configuration()
{
AutomaticMigrationsEnabled = true;
}
protected override void Seed(Context.SportsContext context)
{
// This method will be called after migrating to the latest version.
// You can use the DbSet<T>.AddOrUpdate() helper extension method
// to avoid creating duplicate seed data. E.g.
//
// context.People.AddOrUpdate(
// p => p.FullName,
// new Person { FullName = "Andrew Peters" },
// new Person { FullName = "Brice Lambson" },
// new Person { FullName = "Rowan Miller" }
// );
//
}
}
As you can see this DbMigrationsConfiguration takes in my SportsContext which is also defined in the contexts assembly (Contexts folder)
public class SportsContext : IDbContext
{
private readonly DbContext _context;
public SportsContext()
{
_context = new DbContext("SportsContext");
}
public void Dispose()
{
_context.Dispose();
}
public IDbSet<T> GetEntitySet<T>() where T : class
{
return _context.Set<T>();
}
public void ChangeState<T>(T entity, EntityState state) where T : class
{
_context.Entry(entity).State = state;
}
public void SaveChanges()
{
_context.SaveChanges();
}
}
This implements IDbContext which is defined in the Interfaces assembly
public interface IDbContext : IDisposable
{
IDbSet<T> GetEntitySet<T>() where T : class;
void ChangeState<T>(T entity, EntityState state) where T : class;
void SaveChanges();
}
In my UnitsOfWork assembly I have the following class
public class SportUnitOfWork : IUnitofWork
{
private readonly IDbContext _context;
public SportUnitOfWork()
{
_context = new SportsContext();
}
private GenericRepository<Team> _teamRepository;
private GenericRepository<Fixture> _fixtureRepository;
public GenericRepository<Team> TeamRepository
{
get { return _teamRepository ?? (_teamRepository = new GenericRepository<Team>(_context)); }
}
public GenericRepository<Fixture> FixtureRepository
{
get { return _fixtureRepository ?? (_fixtureRepository = new GenericRepository<Fixture>(_context)); }
}
public void Save()
{
_context.SaveChanges();
}
public IDbContext Context
{
get { return _context; }
}
private bool _disposed;
protected virtual void Dispose(bool disposing)
{
if (!_disposed)
{
if (disposing)
{
_context.Dispose();
}
}
_disposed = true;
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
}
For examples sake I have added the GenericRepository class in the Repositories assembly
public class GenericRepository<T> : IGenericRepository<T> where T : class
{
private IDbContext _context;
public GenericRepository(IDbContext context)
{
_context = context;
}
public GenericRepository(IUnitofWork uow)
{
_context = uow.Context;
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (!disposing) return;
if (_context == null) return;
_context.Dispose();
_context = null;
}
public void Add(T entity)
{
_context.GetEntitySet<T>().Add(entity);
}
public void Update(T entity)
{
_context.ChangeState(entity, EntityState.Modified);
}
public void Remove(T entity)
{
_context.ChangeState(entity, EntityState.Deleted);
}
public T FindSingle(Expression<Func<T, bool>> predicate = null, params Expression<Func<T, object>>[] includes)
{
var set = FindIncluding(includes);
return (predicate == null) ? set.FirstOrDefault() : set.FirstOrDefault(predicate);
}
public IQueryable<T> Find(Expression<Func<T, bool>> predicate = null, params Expression<Func<T, object>>[] includes)
{
var set = FindIncluding(includes);
return (predicate == null) ? set : set.Where(predicate);
}
public IQueryable<T> FindIncluding(params Expression<Func<T, object>>[] includeProperties)
{
var set = _context.GetEntitySet<T>();
if (includeProperties != null)
{
foreach (var include in includeProperties)
{
set.Include(include);
}
}
return set.AsQueryable();
}
public int Count(Expression<Func<T, bool>> predicate = null)
{
var set = _context.GetEntitySet<T>();
return (predicate == null) ? set.Count() : set.Count(predicate);
}
public bool Exist(Expression<Func<T, bool>> predicate = null)
{
var set = _context.GetEntitySet<T>();
return (predicate == null) ? set.Any() : set.Any(predicate);
}
}
The problem I have is in the Configuration class which inherits from DbMigrationsConfiguration is expecting a DbContext parameter.
Error is Error 1 The type 'Contexts.Context.SportsContext' cannot be used as type parameter 'TContext' in the generic type or method 'System.Data.Entity.Migrations.DbMigrationsConfiguration'. There is no implicit reference conversion from 'Contexts.Context.SportsContext' to 'System.Data.Entity.DbContext'.
I can change the SportsContext to also inherit from DbContext but then I need to add a reference to EntityFramework 5 in the UnitsOfWork assembly as we want to possibly change or take out each layer without any reference to underlying models which is why i went with this pattern.
As we are looking at adding further contexts and models in the future so wanted to setup a architecture in that we could just add the context, model and then implement the relevant interfaces as and when needed.
A WebAPI Restful Web Service will be interacting with our data via the SportUnitOfWork, if I have understood the patterns correctly.
If anyone has any ideas on how I could do this or anything that I am doing wrong please let me know
thanks in advance Mark
Resolved this by doing the following
Changed my SportsContext class to a BaseContext which is abstract
public abstract class BaseContext : IDbContext
{
protected DbContext Context;
public void Dispose()
{
Context.Dispose();
}
public IDbSet<T> GetEntitySet<T>() where T : class
{
return Context.Set<T>();
}
public void Add<T>(T entity) where T : class
{
DbEntityEntry dbEntityEntry = GetDbEntityEntrySafely(entity);
dbEntityEntry.State = EntityState.Added;
}
public void Update<T>(T entity) where T : class
{
DbEntityEntry dbEntityEntry = GetDbEntityEntrySafely(entity);
dbEntityEntry.State = EntityState.Modified;
}
public void Delete<T>(T entity) where T : class
{
DbEntityEntry dbEntityEntry = GetDbEntityEntrySafely(entity);
dbEntityEntry.State = EntityState.Deleted;
}
public void SaveChanges()
{
// At the moment we are conforming to server wins when handling concurrency issues
// http://msdn.microsoft.com/en-us/data/jj592904
try
{
Context.SaveChanges();
}
catch (DbUpdateConcurrencyException e)
{
//Refresh using ServerWins
var objcontext = ((IObjectContextAdapter) Context).ObjectContext;
var entry = e.Entries;
objcontext.Refresh(RefreshMode.StoreWins, entry);
SaveChanges();
}
}
private DbEntityEntry GetDbEntityEntrySafely<T>(T entity) where T : class
{
DbEntityEntry dbEntityEntry = Context.Entry(entity);
if (dbEntityEntry.State == EntityState.Detached)
{
// Set Entity Key
var objcontext = ((IObjectContextAdapter) Context).ObjectContext;
if (objcontext.TryGetObjectByKey(dbEntityEntry.Entity))
Context.Set<T>().Attach(entity);
}
return dbEntityEntry;
}
}
created in the Context folder a new class called FootballContext which inherits from BaseContext.
public class FootballContext : BaseContext
{
public FootballContext(string connectionstringName)
{
Context = new BaseFootballContext(connectionstringName);
}
}
Created a new folder called DbContexts
In here created the following classes,
public class BaseFootballContext : DbContext
{
public BaseFootballContext(string nameOrConnectionString) : base(nameOrConnectionString)
{
}
public IDbSet<Fixture> Fixtures { get; set; }
public IDbSet<Team> Teams { get; set; }
}
public class MigrationsContextFactory : IDbContextFactory<BaseFootballContext>
{
public BaseFootballContext Create()
{
return new BaseFootballContext("FootballContext");
}
}
now my Configuration class can take in the BaseFootballContext as this is a DbContext.
My UnitOfWork class can now set the context to be FootballContext so does not have to reference EntityFramework.
This works with Migrations as well.
Only problem I have now is to figure out how to get this to work in a disconnected environment as I am having a problem reattaching entities and applying updates.

LINQ to Entities does not recognize the method

I am following this article on MSDN. I ported it to EF Code First.
public interface IUnitOfWork
{
IRepository<Employee> Employees { get; }
IRepository<TimeCard> TimeCards { get; }
void Commit();
}
public class HrContext : DbContext
{
public DbSet<Employee> Employees { get; set; }
public DbSet<TimeCard> TimeCards { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Employee>()
.HasMany(e => e.TimeCards)
.WithOptional(tc => tc.Employee);
}
}
public class SqlRepository<T> : IRepository<T>
where T : class
{
private readonly DbSet<T> entitySet;
public SqlRepository(DbContext context)
{
this.entitySet = context.Set<T>();
}
public void Add(T newEntity)
{
this.entitySet.Add(newEntity);
}
public IQueryable<T> FindAll()
{
return this.entitySet;
}
public T FindById(params object[] keys)
{
return this.entitySet.Find(keys);
}
public IQueryable<T> FindWhere(Expression<Func<T, bool>> predicate)
{
return this.entitySet.Where(predicate);
}
public void Remove(T entity)
{
this.entitySet.Remove(entity);
}
}
public class SqlUnitOfWork : IUnitOfWork, IDisposable
{
private readonly HrContext context;
private IRepository<Employee> employees;
private IRepository<TimeCard> timeCards;
public SqlUnitOfWork()
{
this.context = new HrContext();
}
public IRepository<Employee> Employees
{
get
{
return new SqlRepository<Employee>(context);
}
}
public IRepository<TimeCard> TimeCards
{
get
{
return new SqlRepository<TimeCard>(context);
}
}
public void Commit()
{
this.context.SaveChanges();
}
public void Dispose()
{
context.Dispose();
}
}
var query = from e in unitOfWork.Employees.FindAll()
from tc in unitOfWork.TimeCards.FindAll()
where tc.Employee.Id == e.Id && e.Name.StartsWith("C")
select tc;
var timeCards = query.ToList();
This model is great as it gives me testability. However, running queries like the one above throws this
LINQ to Entities does not recognize the method
'System.Linq.IQueryable`1[DomainModel.Models.TimeCard] FindAll()'
method, and this method cannot be translated into a store expression.
I understand the error but is there any way to avoid it but still keep the repositories for testability?
Your select statement cannot be translated due to the nature of how IQueryable<T> and the query providers work: see this thread for more info What is the difference between IQueryable<T> and IEnumerable<T>?
You can 'help' the linq provider by dividing your expression into separate statements like this:
var ems = unitOfWork.Employees.FindAll();
var tcs = unitOfWork.TimeCards.FindAll();
var query = from e in ems
from tc in tcs
where tc.Employee.Id == e.Id && e.Name.StartsWith("C")
select tc;
Or you can let FindAll() return IEnumerable<T> instead of IQueryable<T> and then your original expression should work.