Question

I'm quite new to EF and have been reading as many tutorials as I can, but there's lot's of conflicting information out there. I've included some code in case my approach is wrong, but essentially I need to figure out how to get EF to allow the DB to generate the GUID for an identity column, currently EF is writing 0's.

I started with an ADO.NET Entity Data Model, I used this in a database first approach. I manually set all of my primary keys to StoreGeneratedPattern=Identity within the edmx. I then used the EF5.x DBContext Generator, this created my classes.

The context looks like:

public partial class Assets : DbContext
{
    public Assets()
        : base(Common.GetConnString(typeof(Assets)))
    {
    }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        throw new UnintentionalCodeFirstException();
    }

    public DbSet<Building> Buildings { get; set; }
    public DbSet<Device> Devices { get; set; }
    public DbSet<Location> Locations { get; set; }
    public DbSet<Manufacturer> Manufacturers { get; set; }
    public DbSet<Model> Models { get; set; }
    public DbSet<OperatingSystem> OperatingSystems { get; set; }
}

The entities are all fairly similar, here is what one looks like:

public partial class Device : IGuidID
{
    public Guid ID { get; set; }
    public Guid ModelID { get; set; }
    public Nullable<Guid> OperatingSystemID { get; set; }
    public Guid LocationID { get; set; }
    public string DeviceName { get; set; }
    public string Description { get; set; }
    public byte[] BinaryIPAddress { get; set; }

    public string IPAddress
    {
        get
        {
            if (this.BinaryIPAddress == null)
                return null;

            return string.Join(".", this.BinaryIPAddress);
        }
        set
        {
            this.BinaryIPAddress = System.Net.IPAddress.Parse(value).GetAddressBytes();
        }
    }

    public virtual Location Location { get; set; }
    public virtual Model Model { get; set; }
    public virtual OperatingSystem OperatingSystem { get; set; }
}

If I create a new device and save it, instead of honoring the settings defined in the edmx I am writing the GUID defined in the new Device which is 00000... I am saving via a unitofwork and repository pattern.

UnitOfWork:

public class UnitOfWork : UnitOfWorkBase
{
    private Repository<Device> _deviceRepository;

    public Repository<Device> DeviceRepository
    {
        get
        {
            if (_deviceRepository == null)
                _deviceRepository = new Repository<Device>(base.Context);

            return _deviceRepository;
        }
    }

    public UnitOfWork()
        : base(new Model.Assets())
    {
    }
}

public class UnitOfWorkBase : IDisposable
{
    private readonly DbContext _context;

    protected DbContext Context
    {
        get { return _context; }
    }

    public UnitOfWorkBase(DbContext context)
    {
        _context = context;
    }

    public void Save()
    {
        _context.SaveChanges();
    }

    // Additional code Dispose, etc.
}

Repository:

public class Repository<TEntity> : GenericRepository<TEntity>
    where TEntity : class, IGuidID
{
    public Repository(DbContext context)
        : base(context)
    {
    }

    // Additional code here(Contains, etc.)
}

public class GenericRepository<TEntity> where TEntity : class
{
    private readonly DbContext _context;
    private readonly DbSet<TEntity> _dbSet;

    public GenericRepository(DbContext context)
    {
        _context = context;
        _dbSet = context.Set<TEntity>();
    }

    public virtual IEnumerable<TEntity> All()
    {
        return _dbSet.AsEnumerable();
    }

    public virtual void Delete(TEntity entityToDelete)
    {
        if (_context.Entry(entityToDelete).State == EntityState.Detached)
            _dbSet.Attach(entityToDelete);

        _dbSet.Remove(entityToDelete);
    }

    public virtual void Insert(TEntity entity)
    {
        _dbSet.Add(entity);
    }

    public virtual void Update(TEntity entityToUpdate)
    {
        if (_context.Entry(entityToUpdate).State == EntityState.Detached)
            _dbSet.Attach(entityToUpdate);

        _context.Entry(entityToUpdate).State = EntityState.Modified;
    }
}

Honestly the behavior doesn't surprise me, if I attach a device with a 0000... ID I would expect it to insert as such, but I'm not sure how to resolve or where things went wrong. Should all my ID's be nullable even though they aren't in the DB? Do I need to do something with mapping? This sort of thing just "worked" when I was still working with Linq to SQL.

Thanks - Derrick

Was it helpful?

Solution 2

I was able to locate a solution here. Essentially editing the edmx file via the properties within VisualStudio is only altering the ConceptualModels. I needed to modify the StorageModels as well, I don't know if there is another way but modifying the XML manually worked for me. I had to add StoreGeneratedPattern="Identity" to the Primary Key property.

<EntityType Name="Devices">
    <Key>
        <PropertyRef Name="DeviceID" />
    </Key>
    <Property Name="DeviceID" Type="uniqueidentifier" Nullable="false" StoreGeneratedPattern="Identity" />
    <!--Additional Properties-->

OTHER TIPS

I think you need to apply the following attribute to your GUID properties

[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid ID { get; set; }

You will need to add the following namespace to your class

using System.ComponentModel.DataAnnotations.Schema;
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top