Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

No value generator is available for properties of type 'Decimal' #2087

Closed
scottengle opened this issue Apr 28, 2015 · 2 comments
Closed

No value generator is available for properties of type 'Decimal' #2087

scottengle opened this issue Apr 28, 2015 · 2 comments
Labels
closed-fixed The issue has been fixed and is/will be included in the release indicated by the issue milestone. type-bug
Milestone

Comments

@scottengle
Copy link

I am working with an existing legacy database table that contains a primary key defined as "numeric(18, 0)". In Entity Framework 7.0.0-beta3, this is mapping to a CLR type of Decimal. The Microsoft.Data.Entity.SqlServer.SqlServerValueGeneratorSelector (and its base class Microsoft.Data.Entity.Identity.ValueGeneratorSelector) do not have a comparison for decimal types defined.

Per the error message (see below), I have two options: 1) set a value for the property before adding the entity or 2) configure a value generator for properties of type 'Decimal'. The database is not configured to allow for inserts that include the primary key, so I believe I'm left with the second option.

How do I configure a value generator for properties of type 'Decimal'?

When I try to modify items in an existing DBSet, I get this error message:

System.NotSupportedException was unhandled by user code
  HResult=-2146233067
  Message=The 'Id' on entity type 'Bar' does not have a value set and no value generator is available for properties of type 'Decimal'. Either set a value for the property before adding the entity or configure a value generator for properties of type 'Decimal'.
  Source=EntityFramework.Core
  StackTrace:
       at Microsoft.Data.Entity.Identity.ValueGeneratorSelector.Select(IProperty property)
       at Microsoft.Data.Entity.SqlServer.SqlServerValueGeneratorSelector.Select(IProperty property)
       at Microsoft.Data.Entity.Identity.ValueGeneratorCache.GetGenerator(IProperty property)
       at Microsoft.Data.Entity.ChangeTracking.ValueGenerationManager.MayGetTemporaryValue(IProperty property)
       at Microsoft.Data.Entity.ChangeTracking.StateEntry.MayGetStoreValue(IProperty property)
       at System.Linq.Enumerable.WhereEnumerableIterator`1.MoveNext()
       at System.Collections.Generic.List`1..ctor(IEnumerable`1 collection)
       at System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source)
       at Microsoft.Data.Entity.ChangeTracking.StateEntry.MayGetStoreValue()
       at Microsoft.Data.Entity.ChangeTracking.StateEntry.PrepareToSave()
       at Microsoft.Data.Entity.ChangeTracking.StateManager.<>c.<SaveChanges>b__28_1(StateEntry e)
       at System.Linq.Enumerable.WhereSelectEnumerableIterator`2.MoveNext()
       at System.Collections.Generic.List`1..ctor(IEnumerable`1 collection)
       at System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source)
       at Microsoft.Data.Entity.ChangeTracking.StateManager.SaveChanges()
       at Microsoft.Data.Entity.DbContext.SaveChanges()
       ...
  InnerException: 

My model:

namespace Foo.Models
{
    public class Bar
    {
        public decimal Id { get; set; }
        public string Name { get; set; }
        public string Password { get; set; }
        public DateTimeOffset LastModified { get; set; }
    }
}

My model context:

namespace Foo.Models
{
    public class BarContext : DbContext
    {
        public DbSet<Bar> Bars { get; set; }

        public BarContext(DbContextOptions<BarContext> options)
            : base(options)
        { }

        protected override void OnConfiguring(DbContextOptions options)
        {
        }

        protected override void OnModelCreating(ModelBuilder builder)
        {
            builder.Entity<Bar>(e =>
               {
                   e.Metadata.SqlServer().Table = "BARS";
                   e.Property(c => c.Id).Metadata.SqlServer().Column = "BAR_ID";
                   e.Property(c => c.Id).Metadata.SqlServer().ColumnType = "numeric";
                   e.Property(c => c.Name).Metadata.SqlServer().Column = "BAR_NAME";
                   e.Property(c => c.LastModified).Metadata.SqlServer().Column = "LAST_MODIFIED_DTM";
               });

            builder.Entity<Bar>()
                .Key(e => e.Id);

            builder.Entity<Bar>()
                .Property(e => e.Name)
                .MaxLength(50)
                .Required();

            builder.Entity<Bar>()
                .Property(e => e.Password)
                .MaxLength(25)
                .Required();
        }

        public override int SaveChanges()
        {
            ChangeTracker.DetectChanges();

            foreach(var item in ChangeTracker.Entries<Bar>()
                .Where(e => e.State == EntityState.Modified || e.State == EntityState.Added))
            {
                var prop = Model.GetEntityType(typeof(Bar)).GetProperty("LastModified");
                item.StateEntry[prop] = (DateTimeOffset) DateTime.Now;
            }

            return base.SaveChanges();
        }
    }
}

My data service:

namespace Foo.Models
{
    public class BarSvc : IBarSvc
    {
        private BarContext db;

        public BarSvc(BarContext context)
        {
            db = context;
        }

        public Bar AddBar(Bar bar)
        {
            db.Bars.Add(bar);

            if(db.SaveChanges() > 0)
            {
                return bar;
            }
            return null;
        }

        public bool DeleteBar(int id)
        {
            var bar = db.Bars.FirstOrDefault(x => x.Id == id);
            if(bar != null)
            {
                db.Bars.Remove(bar);
                return db.SaveChanges() > 0;
            }
            return false;
        }

        public Bar GetBar(int id)
        {
            return db.Bars.FirstOrDefault(x => x.Id == id);
        }

        public IEnumerable<Bar> GeBars()
        {
            return db.Bars.OrderBy(x => x.Name).AsEnumerable();
        }

        public Bar UpdateBar(int id, Bar bar)
        {
            var existingBar = db.Bars.FirstOrDefault(x => x.Id == id);
            if(existingBar == null)
            {
                return null;
            } 

            existingBar.Name = bar.Name;
            existingBar.Password = bar.Password;

            db.Bars.Update(existingBar);

            if(db.SaveChanges() > 0)
            {
                return existingBar;
            }
            else
            {
                return null;
            }
        }
    }
}
@scottengle
Copy link
Author

Update: this issue is still present in 7.0.0-beta4

   at Microsoft.Data.Entity.ValueGeneration.ValueGeneratorSelector.Create(IProperty property)
   at Microsoft.Data.Entity.SqlServer.SqlServerValueGeneratorSelector.Create(IProperty property)
   at Microsoft.Data.Entity.Utilities.ThreadSafeDictionaryCache`2.GetOrAdd(TKey key, Func`2 factory)
   at Microsoft.Data.Entity.ValueGeneration.ValueGeneratorCache.GetOrAdd(IProperty property, Func`2 factory)
   at Microsoft.Data.Entity.SqlServer.SqlServerValueGeneratorSelector.Select(IProperty property)
   at Microsoft.Data.Entity.ChangeTracking.Internal.ValueGenerationManager.MayGetTemporaryValue(IProperty property)
   at Microsoft.Data.Entity.ChangeTracking.Internal.InternalEntityEntry.MayGetStoreValue(IProperty property)
   at System.Linq.Enumerable.WhereEnumerableIterator`1.MoveNext()
   at System.Collections.Generic.List`1..ctor(IEnumerable`1 collection)
   at System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source)
   at Microsoft.Data.Entity.ChangeTracking.Internal.InternalEntityEntry.MayGetStoreValue()
   at Microsoft.Data.Entity.ChangeTracking.Internal.InternalEntityEntry.PrepareToSave()
   at Microsoft.Data.Entity.ChangeTracking.Internal.StateManager.<>c.<SaveChanges>b__27_1(InternalEntityEntry e)
   at System.Linq.Enumerable.WhereSelectEnumerableIterator`2.MoveNext()
   at System.Collections.Generic.List`1..ctor(IEnumerable`1 collection)
   at System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source)
   at Microsoft.Data.Entity.ChangeTracking.Internal.StateManager.SaveChanges()
   at Microsoft.Data.Entity.DbContext.SaveChanges()
   at PartnerData.Models.PartnerContext.SaveChanges() in C:\projects\PartnerData\src\PartnerData\Models\PartnerContext.cs:line 56
   at PartnerData.Data.PartnerDataSvc.UpdatePartner(Int32 id, Partner partner) in C:\projects\PartnerData\src\PartnerData\Data\PartnerDataSvc.cs:line 62
   at PartnerData.API.Controllers.PartnerDataController.UpdatePartner(Int32 id, Partner partner) in C:\projects\PartnerData\src\PartnerData\API\PartnerDataController.cs:line 88

ajcvickers added a commit that referenced this issue May 1, 2015
This allows some form of temporary value generation to happen for any kind of strange key types. Fixes Issue #2087.
ajcvickers added a commit that referenced this issue May 4, 2015
This allows some form of temporary value generation to happen for any kind of strange key types. Fixes Issue #2087.
@ajcvickers ajcvickers added this to the 7.0.0-beta5 milestone May 4, 2015
@ajcvickers
Copy link
Member

This should be fixed now.

@ajcvickers ajcvickers added the closed-fixed The issue has been fixed and is/will be included in the release indicated by the issue milestone. label Oct 15, 2022
@ajcvickers ajcvickers modified the milestones: 1.0.0-beta5, 1.0.0 Oct 15, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
closed-fixed The issue has been fixed and is/will be included in the release indicated by the issue milestone. type-bug
Projects
None yet
Development

No branches or pull requests

2 participants