I have a problem when adding new values with a many to many mapping in Entity Framework. I know about the unit of work pattern
but in our solution we would like to keep a simple repository pattern and not a unit of work class that contains everything. Is this possible or should I just implement Unit of Work
right away?
If I don't use iSupplierRepository below a supplier will be added, but it will always add a new one even though there already exists one with that name.
Error:
The relationship between the two objects cannot be defined because they are attached to different ObjectContext objects.
Repository example:
public class SupplierRepository : IntEntityRepository<Supplier, DbContext>, ISupplierRepository
{
public SupplierRepository(DbContext context) : base(context, context.Suppliers)
{
}
}
Inherited repositories:
public class IntEntityRepository<TEntity, TContext> : EntityRepository<TEntity, TContext, int>
where TEntity : class, IEntity<int>
where TContext : BaseIdentityDbContext
{
public IntEntityRepository(TContext context, IDbSet<TEntity> set) : base(context, set)
{
}
public override async Task<TEntity> GetAsync(int id)
{
return (await GetAsync(entity => entity.Id == id)).SingleOrDefault();
}
...
public abstract class EntityRepository<TEntity, TContext, TId> : IEntityRepository<TEntity, TId>
where TEntity : class, IEntity<TId>
where TContext : BaseIdentityDbContext
{
protected TContext Context { get; }
protected IDbSet<TEntity> Set { get; }
protected EntityRepository(TContext context, IDbSet<TEntity> set)
{
Context = context;
Set = set;
}
public abstract Task<TEntity> GetAsync(TId id);
...
Unity:
container.RegisterType<ISupplierRepository, SupplierRepository>();
container.RegisterType<IContactRepository, ContactRepository>();
Controller:
private readonly IContactRepository iContactRepository;
private readonly ISupplierRepository iSupplierRepository;
public ContactsController(IContactRepository iContactRepository, ISupplierRepository iSupplierRepository)
{
this.iContactRepository = iContactRepository;
this.iSupplierRepository = iSupplierRepository;
}
[HttpPut]
[Route("UpdateContact/{id}")]
public async Task<IHttpActionResult> UpdateContact(ContactViewModel contactVm, int id)
{
try
{
var supplierList = new List<Supplier>();
foreach (var contactVmSupplier in contactVm.Suppliers)
{
var supplier = await iSupplierRepository.GetAsync(contactVmSupplier.Id);
supplierList.Add(supplier);
}
var contactOriginal = await iContactRepository.GetAsync(id);
var updatedContact = Mapper.Map<ContactViewModel, Contact>(contactVm, contactOriginal);
updatedContact.Suppliers = supplierList;
await iContactRepository.UpdateAsync(updatedContact);
return Ok();
}
catch (Exception e)
{
throw new Exception("Could not update a contact", e);
}
}
Viewmodels:
public class ContactViewModel
{
public int Id { get; set; }
public string Name { get; set; }
public ICollection<SupplierViewModel> Suppliers { get; set; }
}
public class SupplierViewModel
{
public int Id { get; set; }
public string Name { get; set; }
}
Models:
public class Contact : IEntity<int>
{
public Contact()
{
Suppliers = new List<Supplier>();
}
[Key]
public int Id { get; set; }
public DateTime Created { get; set; }
public DateTime Updated { get; set; }
public string Name { get; set; }
public ICollection<Supplier> Suppliers { get; set; }
}
public class Supplier: IEntity<int>
{
public Supplier()
{
Contacts = new List<Contact>();
}
[Key]
public int Id { get; set; }
public DateTime Created { get; set; }
public DateTime Updated { get; set; }
public string Name { get; set; }
public virtual ICollection<Contact> Contacts { get; set; }
}