2

I'd like to create a generic C# class with a method that will add a row to a database using Entity Framework.

I have one table called Address. I've written the following code to add an address to the database:

public class AddressExchange
{
    public int Insert(Address address)
    {
        using (var db = new DemoWebEntities())
        {
            //db.AddObject("Address", address);
            db.Addresses.AddObject(address);
            db.SaveChanges();
            return address.Id;
        }
    }
}

I would like to write a generic class that will perform this operation for any entity in my EDMX. I think that it should look something like this:

public class EntityExchange<T, KeyType>
{
    public KeyType Insert(T t)
    {
        using (var db = new DemoWebEntities())
        {
            // The entity set name might be wrong.
            db.AddObject(typeof(T).Name, t);                

            // EF doesn't know what the primary key is.
            return t.Id;
        }
    }
}

I think it may be possible to use the AddObject method to add the object to the database, but the entityset name is not necessarily the same as the type name, especially if it has been pluralized!

I also want to return the primary key to the caller, but I don't know how to tell which field contains the primary key.

Vivian River
  • 31,198
  • 62
  • 198
  • 313

4 Answers4

3

This might be reliant on a particular version on Entity framework however this is how I do it

public void Create(T entity)
{
    using (var db = new DemoWebEntities())
    {
        db.Set<T>().Add(entity);
    }
}
NinjaNye
  • 7,046
  • 1
  • 32
  • 46
  • It looks like that does depend on a certain version. What I'm looking at right now is using reflection to "discover" which ObjectSet is of the type I want to add (and then remembering it because reflection is expensive). – Vivian River Jul 19 '13 at 15:11
3

I have a generic InsertOrUpdate method in a generic repository that also ensures proxies are created. (Proxies are required to support lazy loading and if you create an entity using "new", then proxies are not created). See the question here

public class RepositoryBase<T> : IRepository<T> where T : ModelBase
{
    public virtual T InsertOrUpdate(T e)
    {
        DbSet<T> dbSet = context.Set<T>();

        //Generate a proxy type to support lazy loading
        T instance = dbSet.Create();

        DbEntityEntry<T> entry;
        if (e.GetType().Equals(instance.GetType()))
        {
            //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. 
            //Attach the proxy
            //Need to set the ID before attaching or we get 
            //The property 'ID' is part of the object's key 
            //information and cannot be modified when we call SetValues
            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 abstract class ModelBase
{
    public int ID { get; set; }
}

Note that all the models inherit ModelBase so that handles the ID issue and I return the entity rather than just the ID. That is probably not strictly necessary since a reference to the entity is passed in and EF performs fixup on the ID anyway so you can always access it from the refernce passed in.

Community
  • 1
  • 1
Colin
  • 22,328
  • 17
  • 103
  • 197
0

For the primary key issue, can you use partial classes to make your entities implement an interface, something like this:

public interface IEntity
{
    Guid PrimaryKey { get; }
}

Your entity classes would then return the appropriate value:

public partial class EntityType : IEntity
{
    public Guid PrimaryKey
    {
        get
        {
            return this.WhateverId; // Return the primary key
        }
     }
}

Then, constrain your method to only accept IEntity:

public class EntityExchange<T, KeyType> where T : IEntity

And finally return the primary key after the insert:

return t.PrimaryKey;
TheNextman
  • 12,428
  • 2
  • 36
  • 75
0

May be it can help you.

public T Add(T model)
    {
        using (BigConceptEntities entity = new BigConceptEntities())
        {
            entity.Set<T>().Add(model);
            entity.SaveChanges();
            return model;
        }
    }
Rahul Jha
  • 874
  • 1
  • 11
  • 28
  • Clearly not what the OP wants: http://stackoverflow.com/questions/17748956/how-to-create-generic-ef-insert-method#comment25879681_17749211 – Gert Arnold Nov 27 '14 at 14:27