Automatic/Smart insert “itself” object

2019-02-26 13:49发布

I'd like to insert my UserCompany object into the database trought a single method. Such as passing the element to this function, take it and "insert in the right table".

Usually in Entity (such as LINQ to XML) I do somethings like:

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

but the problem here is that I need to specify the table UsersCompany and Company before using the .Add(). I'd like (since I want to do ONE function for the insert for each type of object/table) get rid of this. Such as having a:

UserCompany.InsertMySelf();

or

db.SmartAdd(UserCompany);

and it know how to insert the table, where and how, automatically.

Is it possible to do this? Is there any strategies?

3条回答
对你真心纯属浪费
2楼-- · 2019-02-26 14:22

You can solve this with generics:

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

Sorry for using VB... In C#:

public void AddEntities<TEntity>(IEnumerable<TEntity> entities)
   {
     foreach(ent in entities)
     {
         _db.Set<TEntity>.Add(ent);
     }
     _db.SaveChanges();
   }
查看更多
乱世女痞
3楼-- · 2019-02-26 14:22

You need to look at the generic repository. This pattern feeds all the CRUD through one base class. You can then inherit from this class to implement custom repositories where it's necessary

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

References:

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

查看更多
时光不老,我们不散
4楼-- · 2019-02-26 14:25

In your Controller define a repository for yourself along these lines:

public class CompanyController : ApiController
{
    private readonly CompanyRepository _companyRepository;

    public CompanyController()
    {
        _companyRepository= new CompanyRepository(User);
    }

    [HttpPost]
    public Company PostCompany(Company comp)
    {
        _companyRepository.SmartAdd(comp);
    }
}

Define a repository with the definition:

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

There will have to be some adaption to suite your own needs, but this is the general idea.

Although there could potentially be a lot of cases within the switch, I assume you will do object validation and other things regardless, so you can easily do that here too.

Relevant links:

查看更多
登录 后发表回答