Can't find objects which reference entity framework entity - c#

I'm running into an InvalidOperationException because "An entity object cannot be referenced by multiple instances of IEntityChangeTracker." on the first line of EntityFrameWorkRepository.Create().
I know this is due to having multiple database contexts, but in this case I'm a bit lost as the code has no obvious second context since all database access goes through a designated object whose sole purpose is managing database contexts. This was done as the web application in question is fairly interactive and so the user is constantly creating new objects which must be saved in the database. This was causing issues with the previous design, which used locking and a single context, thus the code was refactored and works, except for the method in question.
EF class:
public class EntityFrameWorkRepository<TKey, TEntity> : IDisposable, IRepository<TKey,TEntity> where TEntity: class
{
private readonly IDbContext _context;
private IDbSet<TEntity> _entities;
public EntityFrameWorkRepository()
{
_context = new ApplicationDbContext();
}
private IDbSet<TEntity> Entities
{
get { return _entities ?? (_entities = _context.Set<TEntity>()); }
}
public void Create(TEntity entity)
{
Entities.Add(entity);
_context.SaveChanges();
}
public void Dispose()
{
_context.Dispose();
}
}
The service object used for all DB access:
public class Service : IService
{
public const string Persistance = "Persist";
public const int CacheTaskSeconds = 300; //Check every 5 minutes
public const double IdleMinutes = 30.0;
private readonly IKvpRepository<int, SimulationCollection> _simulationCollectionAppStateRepository;
private readonly UserManager<ApplicationUser> _userManager;
public Service(IKvpRepository<int, SimulationCollection> simulationCollectionAppStateRepository)
{
_userManager = new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(new ApplicationDbContext()));
AddTaskToCache(Persistance, CacheTaskSeconds);
}
public SimulationCollection CreateCollection(Guid userId, string name, string description)
{
using (var _simulationCollectionEFRepository = new EntityFrameWorkRepository<int, SimulationCollectionEntity>())
{
var applicationUser = _userManager.FindById(userId.ToString());
if (applicationUser == null)
throw new ArgumentOutOfRangeException("ApplicationUser matching userId doesn't exist");
var collectionEntity = new SimulationCollectionEntity(applicationUser, name, description);
_simulationCollectionEFRepository.Create(collectionEntity);
return collection;
}
}
}
The object I'm trying to add to the database:
public class SimulationCollectionEntity
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public virtual int Id { get; set; }
public string Name { get; set; }
public virtual ApplicationUser User { get; set; }
public DateTime DateCreated { get; set; }
public string Description { get; set; }
[ForeignKey("SimulationCollectionEntityId")]
public virtual ICollection<SimulationEntity> Simulations { get; set; }
[Obsolete("Only needed for serialization and materialization", true)]
public SimulationCollectionEntity() {}
public SimulationCollectionEntity(ApplicationUser currentUser, string name, string description)
{
User = currentUser;
Name = name;
Description = description;
DateCreated = DateTime.Now;
}
}
Is there an easy way to view what contexts a given object might be attached to? I already checked to see if collectionEntity is attached to _userManager since it has a dbContext, but its state is detached. Does EF maybe expect me to add objects in a different way than I am? I suspect that the attributes in SimulationCollectionEntity might be causing me trouble but I'm new to Entity Framework and I'm not sure. Should I maybe be going for a different design instead like this?

You might want to consider a unit of work like approach where one context is shared among multiple repositories. The accepted answer for this post is a good example. I have seen ContextPerRequest solutions like the one in your example, but I've never been crazy about them. Ideally you want a short lived context that does one thing like add an invoice and two invoice items - a single unit of work. You could then wrap the whole operation in a TransactionScope and have it succeed or fail as a unit.

Related

I get an error when I want to select in constructor in ASP.NET Core Web API

I get an error in my ASP.NET Core Web API project when want to select all content:
System.InvalidOperationException: 'A second operation was started on this context instance before a previous operation completed. This is usually caused by different threads concurrently using the same instance of DbContext. For more information on how to avoid threading issues with DbContext
This is my contentService:
private IContentRepository contentRepository;
private DbContext_CMS dbContext;
public ContentService(IContentRepository contentRepository, DbContext_CMS dbContext )
{
this.contentRepository = contentRepository;
this.dbContext = dbContext;
}
public IEnumerable<ContentInfoDTO> GetAllContent()
{
try
{
IQueryable<Content> contents = contentRepository.GetAll();
IEnumerable<ContentInfoDTO> result = contents.Select(content => new ContentInfoDTO(content)).ToList();
return result;
}
catch (Exception ex)
{
return null;
}
}
This is ContentInfoDTO.cs:
public class ContentInfoDTO
{
public ContentInfoDTO(Content content)
{
try
{
this.Id = content.Id;
this.Title = content.Title;
this.Description = content.Description;
this.BodyHtml = content.BodyHtml;
this.ContentCategories = content.ContentCategories.Select(category => new CategoryInfoDTO(category.FkCmsCategory)).ToList(); //this line error
}
catch (Exception ex)
{
throw;
}
}
public int Id { get; set; }
public string? Title { get; set; }
public string? Description { get; set; }
public string? BodyHtml { get; set; }
public ICollection<CategoryInfoDTO>? ContentCategories { get; set; }
}
This is my CategoryInfoDTO:
public class CategoryInfoDTO
{
public CategoryInfoDTO(Category? category)
{
if (category != null)
{
this.Id = category.Id;
this.Title = category.Title;
this.Description = category.Description;
this.FkParentId = category.FkParentId;
}
}
public int Id { get; set; }
public string? Title { get; set; }
public string? Description { get; set; }
public int? FkParentId { get; set; }
}
And this is my dbContext configured:
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
if (!optionsBuilder.IsConfigured)
{
optionsBuilder
.UseLazyLoadingProxies()
.UseSqlServer("connectionString");
}
}
I also fixed dependency injection, but it didn't work.
service.AddDbContext<DbContext_CMS>();
In contentService:
IEnumerable<ContentInfoDTO> result = contents.Select(content => new ContentInfoDTO(content)).ToList();
in the Select method you start by getting Content entities from the database. At the moment you start getting your first Content, the DbContext instance provided to you by Dependency Injection is in use.
Next, while still inside the Select method, you take the Content entity, create a new ContentInfoDTO object and pass the entity into the constructor. In the constructor of ContentInfoDTO, specifically at the line you get your error,
this.ContentCategories = content.ContentCategories.Select(category => new CategoryInfoDTO(category.FkCmsCategory)).ToList();
you access the ContentCategories property, which is a navigation property belonging to Content. Since the Content entity you passed into the constructor was provided by EF Core, it is being tracked by EF Core, which means when you tried to perform an operation on ContentCategories property, EF Core tried to perform a lazy loading of all the Category entities related to that Content instance. However, since we're still inside the first Select method and the DbContext instance is still in use there, we tried to access the same DbContext from different places at the same time, hence the error.
You could force the retrieval of the ContentCategories collection earlier using the Include method and see if that solves the problem - see eager loading.
Also, I don't think you need to inject your DbContext in contentService, since you seem to use the repository pattern and retrieve your entities from there, I assume the DbContext is already injected into your repository instance.
Edit : it should be lazy loading instead of explicit loading. Also that's assuming that the lazy loading related package is installed and configuration has been done and that the navigation property is virtual. If your situation doesn't cover any of the requirements, your error may be from something else

How to implement expressions in Generic Repository?

I am working on a .Net core project and I have 5 look up tables, so instead of making repository and service for each one I want to make generic repository and generic service for them.
My problem is in implementing FindByID using expressions. I understand the idea behind it but I don't know where or how to use. Any help would be appreciated
Generic Repository Function
private readonly NexusContext _context;
IMapper _mapper;
public GenericRepository(NexusContext context)
{
_context = context;
}
public GenericLookupDTO GetById(Expression<Func<T, bool>> predicate)
{
var obj = _context.Set<T>().Where(predicate);
var objMapped = AutoMapping.mapper.Map<GenericLookupDTO>(obj);
return objMapped;
}
Service Function
private readonly IGenericRepository<T> _genericRepository;
private readonly IUnitOfWork _unitOfWork;
public ConfigurationService(IGenericRepository<T> genericRepository, IUnitOfWork unitOfWork)
{
this._genericRepository = genericRepository;
this._unitOfWork = unitOfWork;
}
List<Errors> errors = new List<Errors>();
try
{
var obj = _genericRepository.GetById(predicate);
if (obj == null)
{
errors.Add(new Errors("404", "Couldn't find configration"));
return new GenericResponse<GenericLookupDTO>(errors, new GenericLookupDTO());
}
await _unitOfWork.CompleteAsync();
return new GenericResponse<GenericLookupDTO>("1", "Success", obj);
}
catch (Exception ex)
{
errors.Add(new Errors(ex.HResult.ToString(), ex.InnerException.Message));
return new GenericResponse<GenericLookupDTO>(errors, new GenericLookupDTO());
}
Controller function
private readonly IConfigurationService<LutNationality> _configurationService;
public NationalityController(IConfigurationService<LutNationality> configurationService)
{
this._configurationService = configurationService;
}
[HttpGet("Id")]
[ProducesResponseType(typeof(GenericLookupDTO), (int)HttpStatusCode.OK)]
public async Task<IActionResult> GetByIdAsync()
{
var result = await _configurationService.GetByIdAsync(//what should i pass here);
if (result.operationSuccess)
return Ok(result);
return BadRequest(result);
}
First look up Table
public partial class LutGender
{
public int Id { get; set; }
public string Value { get; set; }
}
Second look up Table
public partial class LutNationality
{
public int Id { get; set; }
public string Value { get; set; }
}
Generic DTO
public class GenericLookupDTO
{
public int Id { get; set; }
public string value { get; set; }
}
The repository pattern is already implemented by the DbSet<T> and consists in few operations over your entity to store and retrive him from an abstracted data store. Just your entity, it's very important on DDD.
But, I know that sometimes we need to put another layer of abstraction over this, to deal with another databases like nosql, for example.
In this case, usually we create a gereneric repository, and it's needed to supply a way to make operations based on what type this repository is. To accomplish this, we need to define a common interface for our entities with an Id and implement this on those entities:
public interface IEntity
{
Guid Id (get; set;}
}
That way, constraining your generic repository to this type of interface provides you ability to access the Id on the methods.
public class GenericRepository<T> : IGenericRepository<T> where T : IEntity
{
private readonly NexusContext _context;
IMapper _mapper;
public GenericRepository(NexusContext context)
{
_context = context;
}
public GenericLookupDTO GetById(Guid id)
{
var obj = _context.Set<T>().FirstOrDefault(x => x.Id = id);
var objMapped = AutoMapping.mapper.Map<GenericLookupDTO>(obj);
return objMapped;
}
}
I really recomend you to don't return DTOs from repository, if you need to aggregate data from many different entities that are not related, use a different layer of data access, very simplified, and create freely your own queries, using dapper or even EF but projecting directly DTOs.
If the DTO is identical of an entity, in this case use the repository to retrieve the entity and on application layer map this entity to a DTO.
When you have time, take a look at DDD principles to clarify a little bit more those subjects.
Back to your example, on the controller you will need to inject the right type of generic repository, like:
IGenericRepository<Customer> customerRepository
and configure your dependecy injection container to resolve generic types, like:
services.AddTransient<IGenericRepository<>, GenericRepository<>>();
The service will rely just on IGenericRepository<T> as you did.
But, if you want to query freely your entities, I recommend you make use of OData or GraphQl, that will provides you more control over queries.
I'm tried to be very simplistic here, so, I hope that i could clarify things a little bit more for you!

C# Entity Framework (Code first), Implementing CRUD Operations on Model

I just wondering if you can store a function in a model (CRUD transactions)
that will look something like this:
My Existing code:
public class tbluser
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int id { get; set; }
[Required(ErrorMessage = "Username is required")]
public string username { get; set; }
[Required(ErrorMessage = "Password is required")]
public string password { get; set; }
public static List<tbluser> list()
{
using (var db = new sample())
{
var user = db.tbluser.ToList();
return user;
}
}
}
What i want:
public class tbluser:DbContext
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int id { get; set; }
[Required(ErrorMessage = "Username is required")]
public string username { get; set; }
[Required(ErrorMessage = "Password is required")]
public string password { get; set; }
public static List<tbluser> list()
{
return this.toList();
}
}
I just want to ask also if that method of implementing Entity Framework is ok.
Here is a quick example of how you might setup a simple Code First implementation to get started.
First, define your User model. The Key attribute on an integer type automatically configures the identity property for you. Then, you may want an index on username if you plan to do frequent lookups by username (to get user details or to validate a password).
public class User
{
[Key] // Becomes identity by default
public int Id { get; set; }
[Index("IX_User_Username", IsUnique = true)]
public string Username { get; set; }
public string Password { get; set; }
}
Then, you can define
public class AppDataContext : DbContext
{
public AppDataContext() : base("name=DBConnection") { }
public DbSet<User> Users { get; set; }
}
You will just need to be sure there is a connection string in your config file to match the name passed there.
<connectionStrings>
<add name="DBConnection" providerName="System.Data.SqlClient"
connectionString="Data Source=instancePath;Initial Catalog=dbName;Integrated Security=true;MultipleActiveResultSets=True" />
</connectionStrings>
This would now allow you to create repos such as this:
public class UserRepo : IDisposable
{
public Lazy<AppDataContext> _db = new Lazy<AppDataContext>(() => new AppDataContext());
public IQueryable<User> Get() => _db.Value.Users.AsQueryable();
public IList<User> GetAll() => _db.Value.Users.ToList();
public void Dispose()
{
if (_db.IsValueCreated)
_db.Value.Dispose();
}
}
So then you can either use the repo or the context directly.
// Use the repo
using (var userRepo = new UserRepo())
{
var allUsers = userRepo.GetAll();
var user = userRepo.Get().FirstOrDefault(m => m.Username == "myUsername");
}
// Or just use the data context
using (var db = new AppDataContext())
{
var allUsers = db.Users.ToList(); // Get all users
var user = db.Users.FirstOrDefault(m => m.Username == "myUsername");
}
For more information, here are some useful links with great details:
Simple Example
Data Annotations
Initializer Config
Migrations
Code like this is going to be heavily problematic.
In the first example you are tightly coupling an instance of a DbContext to an entity. Calling tblUser.list() will return a list of User entities, but these will now be outside of the scope of a DbContext. (Due to the using() block closure) This means that any lazy load calls to retrieve related entities will fail and you cannot persist any changes to the entities until they are re-attached to another DbContext. This gets very messy, very fast.
In the second example you would be extending a DbContext, meaning each "entity" is effectively scoping a DbContext use to populate instances of itself. You can't just "static" wrap the method because that wouldn't have visibility to the non-static DbSets inherited from DbContext.
This would be horrible in terms of performance, and from a code perspective would look plain weird:
I.e.
using (var user = new tbluser)
{
var users = user.list(); // not static.
// .. Do stuff..
}
To make it static would be problematic because a DbContext would need to be static-scoped inside tbluser
public class tbluser
{
private static MyContext _context = new MyContext();
// ...
public static List<tbluser> list()
{
return _context.tblusers.ToList();
}
}
And this may still have issues, such as how the static instance is disposed, before it was remotely functional but I certainly cannot recommend an approach like this.
Instead, use the DbContext as it is intended. Look at IoC containers like Unity or Autofac to manage the lifetime scope for for the DbContext and inject an instance as a dependency into classes that need it, or at a minimum wrap it in a using() {} block and treat it like an repository with it's DbSets.
There are lots of examples of using the DbContext effectively, using Repositories and Unit of Work patterns with dependency injection. Master these before attempting to spin up something unique. Future developers looking at your code will thank you. :)
There is one famous principle called "Separation of Concerns" that will get very angry if you do this. My advice is to keep the code simple, meaningful and loosely coupled.

Abstract away the DAL from Entity Framework implementation

First of all I'm sorry if this is going to be a long post, but I don't know how to explain the problem in the correct way without the required details.
I'm having troubles finding a way to abstract my DAL from an Entity Framework implementation. The project I'm working on is very small, but if in future I'd want to switch to another ORM like NHibernate, or just plain ADO.NET, I'd like to write code just for the implementation, not the entire DAL.
Say I have these entities in my MyWallet.DAL:
public interface IWallet {
long Id { get; set; }
float TotalAmountOfMoney { get; set; }
long CurrencyId { get; set; }
ICurrency Currency { get; set; }
DateTime RecordedOn { get; set; }
ICollection<IMoneyMovement> MoneyMovements { get; set; }
}
public interface ICurrency {
long Id { get; set; }
char Symbol { get; set; }
string Code { get; set; }
string Description { get; set; }
}
public interface IMoneyMovement {
long Id { get; set; }
float Amount { get; set; }
string Description { get; set; }
long WalletId { get; set; }
IWallet Wallet { get; set; }
DateTime RecordedOn { get; set; }
DateTime MovedOn { get; set; }
}
As you can see these are plain interfaces which I plan to implement on another library which will contain the actual Entity Framework implementation (say MyWallet.DAL.EntityFramework). Of course I'm going to decorate the entities implementation with Entity Framework specific attributes as [Key] or [ForeignKey] and stuff like that.
I also defined some repository in MyWallet.DAL like IWalletRepository, IMoneyMovementRepository, ICurrencyRepository to gain access to the entities. Actually I don't know if this is the right way to design access to the entities. Of course I also defined factories to get the concrete implementation of the entities.
In my business layer I defined services to handle the object request, work with the DAL entities and return a business object, like this:
public class WalletService {
private readonly IWalletRepository _walletRepository;
private readonly IWalletFactory _walletFactory;
public WalletService(IWalletRepository walletRepository,
IWalletFactory walletFactory) {
_walletRepository = walletRepository;
_walletFactory = walletFactory;
}
public CreatedWallet CreateWallet(CreateWalletRequest request) {
var wallet = _walletFactory.Create();
wallet.CurrencyId = request.CurrencyId;
wallet.TotalAmountOfMoney = request.TotalAmountOfMoney;
wallet.RecordedOn = DateTime.Now;
_walletRepository.Create(wallet);
_walletRepository.SaveChanges();
return new CreatedWallet {
Id = wallet.Id
}
}
}
I thought this was going to work seamlessly, or at worst - in a situation when I've got more than one repository - I could share the DataContext so I'd need to fire the SaveChanges method on just one to reflect the changes on the database.
The problem is with the repository implementation, in this case I'll continue with Entity Framework:
public class EFDataContext : DbContext {
public EFDataContext() : base ("name=MyConnectionString") {
}
public virtual DbSet<EFWallet> Wallets { get; set; }
public virtual DbSet<EFMoneyMovement> MoneyMovements { get; set; }
public virtual DbSet<EFCurrency> Currencies { get; set; }
}
public class EFWalletRepository : IWalletRepository {
private readonly EFDbContext _dataContext;
public EFWalletRepository(EFDbContext dataContext) {
_dataContext = dataContext ?? new EFDbContext();
}
public int SaveChanges() {
return _dataContext.SaveChanges();
}
public void Dispose() {
_dataContext.Dispose();
}
public void Create(IWallet wallet) {
...???
}
}
Now that's the problem: how do I work with interfaces when the DataContext knows only about concrete implementations? Am I doing this all wrong?
UPDATE:
Ok so, basically, as stated out by #TomTom, why fight Entity Framework when you could just embrace its power? I guess I'll just let EF be the abstraction. In fact, by letting EF act as the DAL, you can just focus on the business logic of your project.
And to put it all together and respond to #tdragon regarding the repositories / unit of work issue: yes, I could either wrap multiple repositories inside an unit of work or simply let the DbContext be the unit of work:
public class EFWalletRepository : IWalletRepository {
private readonly EFDbContext _dataContext;
public EFWalletRepository() {
_dataContext = new EFDbContext();
}
public void Dispose() {
_dataContext.Dispose();
}
public IEnumerable<Wallet> Wallets {
get { return _dataContext.Wallets; }
}
public void SaveWallet(Wallet wallet) {
if (wallet.Id == 0) {
_dataContext.Wallets.Add(wallet);
} else {
var databaseEntry = _dataContext.Wallets.Find(wallet.Id);
//update properties
}
_dataContext.SaveChanges();
}
}
Simply speaking: yes, you do it wrong. You introduce a bad abstraction (that costs you dearly in functionality) "because of". EF already is an abstraction.
Any abstraction on top of it will cost you in terms of functionality used - which in terms of databases comes with a big performance impact. Want an example? "Include" to preload navigation properties (instead of lazy loading). You will have to work around this and a lot of more detailed behavior that is ORM specific - for the gain of having what? And if you give up on those higher more specific functions your performance WILL suffer.
I can't see any reason to abstract your model (entities). Do you expect them to change when you change the way you access your database?
But if you want to keep it that way, you can make your repository interfaces generic, and pass the concrete entity type when defining repository, so you would end up with:
public class EFWalletRepository : IWalletRepository<EFWallet>
{
public void Create(EFWallet wallet)
{
_dataContext.Add(wallet);
}
}
Other suggestions:
You should not expose sets for your model properties. It's against OOP rules - you should rather expose some methods to manipulate the objects, the state should be more internal.
You probably should not add SaveChanges() method to your repository - this should be a "unit of work" job to commit all changes to the database.
You would face a problem when you would use more than one repository in your service layer, as you create a new DbContext for repository, when you should have one for single "unit of work".

Configure EF DAO to return detached entities

Is it possible (with attributes or something) to configure DAO methods to return detached objects? I am keen to do this, because I want to make sure that the DAO pre-fetches any fields and relationships that might be required by downstream code on return from the DAO. If the entities are detached, then an exception will be thrown and we can identity the issue easily. With lazy resolution of relationships, you potentially get multiple additional requests to the DB without realising it.
For example, let's say I have a DAO class:
public class TestDao
{
private readonly MyContext _db;
public TestDao(MyContext db)
{
_db = db;
}
public List<Group> AllGroups()
{
return _db.Groups.ToList();
}
}
And then say that I have a client of the Dao:
public void TestGetAllGroups()
{
var groups = _testDao.AllGroups();
foreach (var group in groups)
{
var x = group.Memberships;
Console.WriteLine( group.id + ":" + x.Count );
}
}
This code works, but each iteration in the test harness causes a new hit to the DB because the DB hasn't pre-fetched (included) the Memberships relationship.
I'm looking for the best way to get this code to throw an exception, saying that group.Memberships is null or something. If the Group instances were detached upon exit from TestDao.AllGroups(), then this would do the trick, and alert us to the fact that the DAO needs to include the Memberships before returning from the AllGroups() method
Looks like you can disable Lazy Loading of relationships. In my Context class:
public partial class MyContext : DbContext
{
static MyContext()
{
Database.SetInitializer<MyContext>(null);
}
public MyContext() : this("Name=MyContext")
{
}
public MyContext(string name): base(name)
{
Configuration.LazyLoadingEnabled = false;
}
...
}
However, in addition to this, I need to make sure that the EF entity constructor doesn't create empty lists for the one-to-many relations. These seem to get added by default with the schema-first entity code generation tool:
public partial class Group
{
public Group()
{
//Remove this line!
//this.Memberships = new List<Membership>();
}
public int id { get; set; }
public string name { get; set; }
public virtual ICollection<Membership> Memberships { get; set; }
}
Now, my test harness will throw a NPE unless I put a .Include into the Dao to include Memberships

Categories

Resources