【问题标题】:Automatic/Smart insert "itself" object自动/智能插入“自身”对象
【发布时间】:2013-10-03 13:24:41
【问题描述】:

我想通过单一方法将我的UserCompany 对象插入数据库。比如将元素传递给这个函数,取它并“插入右表”。

通常在实体中(例如 LINQ to XML)我会做类似的事情:

db.Company.UsersCompany.Add(UserCompany);
db.SubmitChanges();

但这里的问题是我需要在使用.Add() 之前指定表UsersCompanyCompany。 我想(因为我想为每种类型的对象/表的插入执行一个函数)摆脱这个。比如有一个:

UserCompany.InsertMySelf();

db.SmartAdd(UserCompany);

它知道如何自动插入表格,在哪里以及如何插入。

可以这样做吗?有什么策略吗?

【问题讨论】:

  • 您的上下文之上的存储库模式?在该方法中根据对象类型切换?
  • 你能给我举个例子吗?
  • 是的,给我几分钟时间输入一些代码。
  • Usually in Entity (such as LINQ to XML) I do somethings like 是什么意思?实体框架和 LINQ to XML 不是一回事。一般来说,您是否尝试过简单地做db.UserCompanies.Add(UserCompany)?如果您的Company 对象是UserCompany 对象的一部分,则应将整个对象图正确插入数据库(即CompanyUserCompany 表)。如果不是这样,请提供您的数据库结构和映射实体,以及您正在尝试的代码。
  • @Yakimych:这只是一个例子。与db.UserCompanies.Add(UserCompany) 一样,我必须指定UserCompanies。所以我每次都需要指定“父”表。这意味着我不能执行一般的“插入”功能,因为我需要预先选择哪个父表是目标。你知道我的意思吗?

标签: .net sql-server entity-framework insert


【解决方案1】:

你可以用泛型解决这个问题:

Public Sub AddEntities(Of TEntity)(entities As IEnumerable(Of TEntity))
   For Each ent In entities
       _db.Set(Of TEntity).Add(ent)
   Next
   _db.SaveChanges()
End Sub

很抱歉使用 VB... 在 C# 中:

public void AddEntities<TEntity>(IEnumerable<TEntity> entities)
   {
     foreach(ent in entities)
     {
         _db.Set<TEntity>.Add(ent);
     }
     _db.SaveChanges();
   }

【讨论】:

    【解决方案2】:

    在您的Controller 中为您自己定义一个存储库:

    public class CompanyController : ApiController
    {
        private readonly CompanyRepository _companyRepository;
    
        public CompanyController()
        {
            _companyRepository= new CompanyRepository(User);
        }
    
        [HttpPost]
        public Company PostCompany(Company comp)
        {
            _companyRepository.SmartAdd(comp);
        }
    }
    

    使用以下定义定义存储库:

    public class CompanyRepository : EFContextProvider<CompanyContext>
    {
        // Fields which can be used for security within the repository.
        public IPrincipal User { get; private set; }
        public string UserName { get; set; }
    
        public CompanyRepository (IPrincipal user)
        {
            User = user;
            UserName = user.Identity.Name;
        }
    
        public DbQuery<Object> SmartAdd(Object obj)
        {
            switch (obj.GetType)
            {
                case "":  // TODO...
                  Context.Company.UsersCompany.Add(UserCompany);
                    break;
    
                default:
                    break;
            }
        }
    

    必须进行一些调整以适应您自己的需求,但这是一般的想法。

    虽然在 switch 中可能存在很多情况,但我假设您无论如何都会进行对象验证和其他事情,因此您也可以在这里轻松地做到这一点。

    相关链接:

    【讨论】:

    • 这是我想要避免的:select case。如果我有 25 张桌子怎么办?带25壳的开关?嗯...不一致...
    • 这怎么不一致?这一切都在一个地方,而且对于使用实际 API 的人来说肯定更易于管理。如果你愿意,你可以进一步分解它并继续抽象它,但我认为这对你的事业没有帮助。否则,请为数据库中的每个对象定义一个类型,然后根据您尝试保存的对象对每个表的模式运行 SQL,以降低性能和空间。
    【解决方案3】:

    您需要查看通用存储库。这种模式通过一个基类提供所有 CRUD。然后,您可以从此类继承以在需要时实现自定义存储库

    public class RepositoryBase<T> : IRepository<T> where T : ModelBase
    {
        private readonly IUnitOfWork _UnitOfWork;
        //https://stackoverflow.com/questions/4442828/entity-framework-4-ctp-4-ctp-5-generic-repository-pattern-and-unit-testable/4458250#4458250
    
    
        protected MyContext Context { get { return _UnitOfWork.Context; } }
    
        public RepositoryBase(IUnitOfWork unitOfWork)
        {
            _UnitOfWork = unitOfWork;
        }
    
        public virtual T InsertOrUpdate(T e)
        {
            DbSet<T> dbSet = Context.Set<T>();
    
            DbEntityEntry<T> entry;
            if (e.GetType().BaseType != null && e.GetType().Namespace == "System.Data.Entity.DynamicProxies")
            {
                //The entity being added is already a proxy type that supports lazy loading
                //just get the context entry
                entry = Context.Entry(e);
            }
            else
            {
                //The entity being added has been created using the "new" operator. 
                //Generate a proxy type to support lazy loading  and attach it
                T instance = dbSet.Create();
                instance.ID = e.ID;
                entry = Context.Entry(instance);
                dbSet.Attach(instance);
    
                //and set it's values to those of the entity
                entry.CurrentValues.SetValues(e);
                e = instance;
            }
    
            entry.State = e.ID == default(int) ?
                                    EntityState.Added :
                                    EntityState.Modified;
    
            return e;
        }
    
        public virtual IQueryable<T> All
        {
            get
            {
                return Context.Set<T>(); 
            }
        }
    
        public virtual IQueryable<T> AllIncluding(params Expression<Func<T, object>>[] includeProperties)
        {
            IQueryable<T> query = All;
            foreach (var includeProperty in includeProperties)
            {
                query = query.Include(includeProperty);
            }
            return query;
        }
    
        public virtual T Find(int id)
        {
            T e = Context.Set<T>().Find(id);
            if (e == null)
                return null;
    
            return e;
        }
    
        public virtual void Delete(int id)
        {
            var e = Context.Set<T>().Find(id);
    
            if (e != null)
                Context.Set<T>().Remove(e);
    
        }
    }
    
    public abstract class ModelBase
    {
        public int ID { get; set; }
    }
    

    参考资料:

    The repository and unit of work patterns

    John Papa's original source

    How to ensure proxies are created when using the repository pattern

    Generic Repository Pattern

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-09-02
      • 1970-01-01
      • 1970-01-01
      • 2014-10-10
      • 2014-06-17
      • 2016-01-28
      • 2017-12-20
      • 1970-01-01
      相关资源
      最近更新 更多