实体框架6 - 使用Unity的依赖注入 - 存储库模式 - 为多对多关系添加或更新异常 [英] Entity Framework 6 - Dependency Injection with Unity - Repository pattern - Add or Update exception for many to many relationship

查看:115
本文介绍了实体框架6 - 使用Unity的依赖注入 - 存储库模式 - 为多对多关系添加或更新异常的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在实体框架中添加多个到多个映射的新值时,我有一个问题。我知道工作模式单元,但在我们的解决方案中,我们希望保留一个简单的存储库模式,而不是包含所有内容的工作类单元。这是否可能,或者我应该立即实施工作单位



如果我不使用iSupplierRepository,将会添加一个供应商,但总是会添加一个新的,即使已经存在一个使用该名称。



错误:


两个对象之间的关系不能定义是因为
它们被附加到不同的ObjectContext对象。


资源库示例:

  public class SupplierRepository:IntEntityRepository< Supplier,DbContext>,ISupplierRepository 
{
public SupplierRepository(DbContext context):base(context,context.Suppliers )
{
}
}

继承的存储库: p>

  public class IntEntityRepository< TEntity,TContext> :EntityRepository< TEntity,TContext,int> 
其中TEntity:class,IEntity< int>
其中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>
其中TEntity:class,IEntity< TId>
其中TContext:BaseIdentityDbContext
{
protected TContext Context {get; }
protected IDbSet< TEntity>设置{get;

protected EntityRepository(TContext context,IDbSet< TEntity> set)
{
Context = context;
Set = set;
}

public abstract任务< TEntity> GetAsync(TId id);
...

Unity:

  container.RegisterType< ISupplierRepository,SupplierRepository>(); 
container.RegisterType< IContactRepository,ContactRepository>();

控制器:

 code> 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任务< 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(供应商);
}

var contactOriginal = await iContactRepository.GetAsync(id);
var updatedContact = Mapper.Map< ContactViewModel,Contact>(contactVm,contactOriginal);
updatedContact.Suppliers = supplierList;

等待iContactRepository.UpdateAsync(updatedContact);
return Ok();
}
catch(异常e)
{
抛出新异常(无法更新联系人,e);
}

}

Viewmodels:

  public class ContactViewModel 
{
public int Id {get;组; }

public string Name {get;组; }

public ICollection< SupplierViewModel>供应商{get;组; }
}

public class SupplierViewModel
{
public int Id {get;组; }

public string Name {get;组;
}

模型:

  public class联系人:IEntity< int> 
{
public Contact()
{
Suppliers = new List< Supplier>();
}

[Key]
public int Id {get;组; }

public DateTime Created {get;组; }

public DateTime更新{get;组; }

public string Name {get;组; }

public ICollection<供应商>供应商{get;组; }

}

public class供应商:IEntity< int>
{
public Supplier()
{
Contacts = new List< Contact>();
}
[Key]
public int Id {get;组; }

public DateTime Created {get;组; }

public DateTime更新{get;组; }

public string Name {get;组; }

public virtual ICollection< Contact>联系人{get;组; }
}


解决方案

一个href =https://www.nuget.org/packages/Unity.AspNet.WebApi =nofollow noreferrer>用于ASP.NET Web API的Unity引导程序包,一个 UnityHierarchicalDependencyResolver 可用,它将为每个 IHttpController 分辨率使用一个新的子容器,有效地使所有注册使用 HierarchicalLifetimeManager 每个请求解析,以便控制器中的所有存储库实例将使用相同的 DbContext



NuGet软件包还将在App_Start中安装一些使用WebActivatorEx的引导代码。您可以使用此方法或更改以与现在正在使用的方式对齐。根据您发布的代码,它将如下所示:

  public static void ConfigureUnity(HttpConfiguration config)
{
var container = new UnityContainer();
container.RegisterType< DbContext>(new HierarchicalLifetimeManager());
container.RegisterType< ISupplierRepository,SupplierRepository>();
container.RegisterType< IContactRepository,ContactRepository>();
config.DependencyResolver = new UnityHierarchicalDependencyResolver(container);
}


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; }
}

解决方案

If you install the Unity bootstrapper for ASP.NET Web API package, a UnityHierarchicalDependencyResolver is available which will use a new child container for each IHttpController resolution effectively making all registrations with a HierarchicalLifetimeManager resolved per request so that all repository instances in a controller will use the same DbContext.

The NuGet package will also install some bootstrapping code in App_Start which uses WebActivatorEx. You can either use this approach or change to align with what you are using right now. Based on your posted code it would look something like:

public static void ConfigureUnity(HttpConfiguration config)
{
    var container = new UnityContainer();
    container.RegisterType<DbContext>(new HierarchicalLifetimeManager());
    container.RegisterType<ISupplierRepository, SupplierRepository>();
    container.RegisterType<IContactRepository, ContactRepository>();
    config.DependencyResolver = new UnityHierarchicalDependencyResolver(container);
}

这篇关于实体框架6 - 使用Unity的依赖注入 - 存储库模式 - 为多对多关系添加或更新异常的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆