Entity Framework 7 Set decimal precision for model builder - entity-framework-core

I have been trying to figure out how to set the decimal precision for EF7 (Beta 4) with no luck.
I was expecting to do something like:
modelBuilder.Entity<SomeClass>().Property(p => p.DecimalProperty).Precision(10, 6)
This does not appear to be available, but I was able to find the following class in the repository in GitHub:
https://github.com/aspnet/EntityFramework/blob/7.0.0-beta4/src/EntityFramework.Relational/RelationalDecimalTypeMapping.cs
There are no examples of using the RelationalTypeMapping classes or method signatures with them. Maybe this is just used as part of the mapping api for retrieving information?
Another place I might expect this to be is the following:
modelBuilder.Entity<SomeClass>().Property(p => p.DecimalProperty).ForRelational().ColumnType()
or
modelBuilder.Entity<SomeClass>().Property(p => p.DecimalProperty).ForSqlServer().ColumnType()
These only takes a string, is this functionality just not implemented yet or am I just not looking in the correct place?
Edit: Just realized that string is probably for .ColumnType("decimal(10,6)") type of solution until this is built out further, still wouldn't mind getting some clarification though as I would prefer not to use strings for this
Edit: after clarification from bricelam I ended up creating the following extension to use for now to avoid using the string, and I appreciate the simplicity of their approach:
public static RelationalPropertyBuilder DecimalPrecision(this RelationalPropertyBuilder propertyBuilder, int precision, int scale)
{
return propertyBuilder.ColumnType($"decimal({precision},{scale})");
}
Usage example:
modelBuilder.Entity<SomeClass>().Property(p => p.DecimalProperty).ForRelational().DecimalPrecision(10,6);
Edit: Making modification for RC1
I haven't tested these out yet, but I just threw together the following 2 samples of what this will probably look like with RC1
public static PropertyBuilder DecimalPrecision(this PropertyBuilder propertyBuilder, string precision, string scale)
{
return propertyBuilder.HasColumnType($"decimal({precision},{scale})");
}
public static PropertyBuilder SqlDecimalPrecision(this PropertyBuilder propertyBuilder, string precision, string scale)
{
return propertyBuilder.ForSqlServerHasColumnType($"decimal({precision},{scale})");
}
Since I have not yet tried this I am not sure which would be the correct usage between "HasColumnType" or "ForSqlServerHasColumnType", but hopefully this will point someone in the right direction.

Your workaround is the design we intended. Instead of having a bunch of "facets" you can set on a type like precision, scale, max length, unicode/ansi, fixed/variable length, etc. We decided to keep it simple: If the default type mapping isn't what you want, tell us what type to use. There have been talks of going back on this decision and reintroducing the "facets". If you feel strongly about it, I would encourage you to create a new issue.
Also note that there are a bunch of other bugs in type mapping right now, but they should be fixed by the time we release beta5.

The example shown seems to be outdated as per EF RC1.
Here is how I set precision on a decimal field.
Say I have an entity
public class Review
{
public int ReviewId { get; set; }
public decimal TotalScore { get; set; } //I want a precision field in DB
public DateTime CreatedOn { get; set; }
[Timestamp]
public byte[] RowVersion { get; set; }
}
then in my context class, on model creating, I instantiate the mapping (I could do the mapping there, but I like to keep it separated)
public class MyDbContext : DbContext
{
public MyDbContext(DbContextOptions<MyDbContext> options ) : base(options)
{
}
public DbSet<Review> Reviews { get; set; }
//etc.
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
//Mappings
new ReviewMap(modelBuilder.Entity<Review>());
//etc..
}
}
and then the mapping. Remember to use the namespace where the Model extensions are:
using Microsoft.Data.Entity; //here is where the extensions are
public class ReviewMap
{
public ReviewMap(EntityTypeBuilder<Review> entityBuilder)
{
entityBuilder.HasKey(r => r.ReviewId);
//Using the column type extension
entityBuilder.Property(r => r.TotalScore)
.HasColumnType($"decimal(5,2)")
.IsRequired(true);
//and this has nothing to do with the example but it's interesting
//to show how to use Sql command to automatically fulfil a value
//when adding a new Entity
entityBuilder.Property(r => r.CreatedOn)
.ValueGeneratedOnAdd()
.HasDefaultValueSql("GETUTCDATE()")
.IsRequired(true);
}
}

Related

Create a table corresponding to enum Entity framework

I followed the below answer to insert enums into database;
How to create a table corresponding to enum in EF6 Code First?
But I am facing one strange issue. Every time I run the application, it additionally enters the last enum. For example, suppose i have three option for enum;
Started, In Progress, Done.
now on first run, it enters the 3 values as expected.
but on second run, there are four rows in database and Done is duplicated. Done is duplicated on each run.
PS:
I have done some changes from above article.
I used DatabaseGenerated(DatabaseGeneratedOption.Identity) instead of DatabaseGenerated(DatabaseGeneratedOption.None)
My table is already in database
I am using code-first approach and just wanted to re-factor code.
Am I doing anything wrong or is there any other solution to solve this?
Enum Class:
namespace ToDO.Data.Models
{
public class TaskStatus
{
private TaskStatusTaskStatusEnum #enum)
{
Id = (int)#enum;
Name = #enum.ToString();
Description = #enum.GetEnumDescription();
}
protected TaskStatus() { } //For EF
[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
[Required, MaxLength(100)]
public string Name { get; set; }
[MaxLength(100)]
public string Description { get; set; }
public static implicit operator TaskStatusTaskStatusEnum #enum) => new TaskStatus(#enum);
public static implicit operator TaskStatusEnumTaskStatus status) => (TaskStatusEnum)status.Id;
}
public enum TaskStatusEnum
{
[Description("Started")]
Started,
[Description("In Progress")]
InProgress,
[Description("Done")]
Done
}
}
EF Extenstion method to add values in database:
public static void SeedEnumValues<T, TEnum>(this IDbSet<T> dbSet, Func<TEnum, T> converter)
where T : class => Enum.GetValues(typeof(TEnum))
.Cast<object>()
.Select(value => converter((TEnum)value))
.ToList()
.ForEach(instance => dbSet.AddOrUpdate(instance));
Result:
Database result
Thanks.
The AddOrUpdate does its compare with the primarykey. Enums starts from 0. This one is not in the database so it is added again. You can use AddOrUpdate(x=>x.Code.. etc

Why the frequent unexplained use of the partial modifier in EF Code First?

In the EF Code first docs and examples, you'll frequently see classes and methods defined using the partial modifier. For example, the following
public partial class Department
{
public int DepartmentID { get; set; }
public DepartmentNames Name { get; set; }
public decimal Budget { get; set; }
}
I understand the general use of the partial keyword by the C# compiler. However, I often see these examples without applying that functionality (i.e., the class is never re-opened elsewhere).
In other examples, I have also seen partial modifiers on methods as well.
Do these modifiers carry some special meaning in an EF Code First context? Can anyone help me understand what's going on?
Given EF makes working with POCOs really easy, this makes it flexible in terms of separating components and pieces. For example, a section that defines your models:
public partial class PurchaseOrder
{
public Int32 ID { get; set; }
public String CustomerName { get; set; }
public Double InvoiceAmount { get; set; }
public virtual ICollection<PurchaseOrderItem> Items { get; set; }
}
Then apply business logic elsewhere:
public partial class PurchaseOrder : IValidatableObject
{
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
// ...
}
}
And maybe extend its functionality another place still:
public partial class PurchaseOrder
{
public void AddItem(PurchaseOrderItem item)
{
// ...
}
}
though as #E.J. Brennan mentions, it's more likely they were generated from a T4 template. This means that anything you did in the generated file would be wiped with every generation; however, if you left the generated item alone, you could still extend it (like I've shown with IValidatableObject or additional methods) without worrying if your changes would be lost.
It wouldn't be unusual to use T4, or another code generator to create the basic classes that map back to your database. If one did that, you would want those classes to be partial so that you could extend those classes in a seperate file - if you extended those classes in the original file, they would get overwritten every time you re-generated the file.
If you hand coded your classes, there would be no need to use the partial on all of them.
You can extend Entity Framework generated types:
The classes only contain properties that are defined in the conceptual model and do not contain any methods. The generated classes are partial.
So, in your new partial classes (not the generated ones) you can define business logic, display attributes, validation logic etc. These classes won't be overwritten, like the generated ones.

In Entity Framework is there a cleaner way of converting an object type to a string representation for storage?

Very minor thing really but it bugs me slightly so I thought I'd ask. I have the POCO entity Setting and I'm using a code first approach to Entity Framework.
public class Setting
{
[Required]
[MaxLength(128)]
public string Name { get; set; }
[Required]
public Type Type { get; set; }
// Added to support the storing of Type in the database via Entity Framework.
// Really would be nice to find a cleaner way but this isn't actually so bad.
public string TypeString
{
get { return Type.ToString(); }
set { Type = Type.GetType(value); }
}
public string Value { get; set; }
}
As you can see for use in code I'd like to actually be using the Type object but to store this I have ended up adding a TypeString property. Via the DbModelBuilder I then hide the Type property.
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder
.Entity<Setting>()
.HasKey(e => e.Name)
.Property(e => e.Name)
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.None);
modelBuilder
.Entity<Setting>()
.Ignore(e => e.Type);
modelBuilder
.Entity<Setting>()
.Property(e => e.TypeString)
.HasColumnName("Type");
base.OnModelCreating(modelBuilder);
}
I just was wondering if there was a way of defining a custom property mapping instead of having to add that extra property to my entity.
UPDATE
My reasoning behind these was actually that I just wanted a quick and easy way for developers to be able to configure a few simple settings by logging in, and it was late and this seemed like a quick solution to allow for several settings of various types.
I suppose if if I wanted some strongly typed settings I'd probably look at a generic implementation of setting such as below:
public class Setting<T>
{
[Required]
[MaxLength(128)]
public string Name { get; set; }
public T Value { get; set; }
}
Though I don't believe that is something that will play nice with Entity Framework.
In part though I'm also curious as for some applications I have multiple clients or stakeholders who can each request slightly different validation rules. As such we usually implement and interface and create an implementation per clients or collections of clients. In order that we can more easily add clients and customise their rules we store which implementation of the interface to create for each client. So persisting type information has proved extremely useful in those cases.
Also it's nice to just explore and understand ways that I can quite happily develop an application whilst reducing the need to think how am I going to persist this, or is this going to play nice with Entity Framework as much as possible.
I'm not aware of any way to persist Type directly, but this may feel a bit better:
public class Settings
{
public Type Type
{
get { return Type.GetType(_TypeString); }
set { _TypeString = value.ToString(); }
}
// Backing Field
protected virtual string _TypeString { get; set; }
}
Then you just need to map the protected _TypeString property (solution from here):
public static StringPropertyConfiguration Property<T>(this EntityTypeConfiguration<T> mapper, String propertyName) where T : class
{
Type type = typeof(T);
ParameterExpression arg = Expression.Parameter(type, "x");
Expression expr = arg;
PropertyInfo pi = type.GetProperty(propertyName,
BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);
expr = Expression.Property(expr, pi);
LambdaExpression lambda = Expression.Lambda(expr, arg);
Expression<Func<T, String>> expression = (Expression<Func<T, string>>)lambda;
return mapper.Property(expression);
}
Then, in your ModelBuilder:
modelBuilder
.Entity<Setting>()
.Property("_TypeString")
.HasColumnName("Type");

How to get EF POCOs from System.Data.Entities.DynamicProxies

My question is the same as this one
However, I don't really see a solution there. Lets say I have a simple model with two POCOs, Country and State.
public class Country
{
public string Code { get; set; }
public string Name { get; set; }
}
public class State
{
public string Code { get; set; }
public string Name { get; set; }
public virtual Country Country { get; set; }
}
When I use the repository to .GetStateByCode(myCode), it retrieves a dynamic proxy object. I want to send that over the wire using a WCF service to my client. The dynamic proxy is not a know type so it fails.
Here are my alternatives. I can set ProxyCreationEnabled to false on the context and then my .GetStateByCode(myCode) gives me a POCO which is great. However, the navigation property in the POCO to Country is then NULL (not great).
Should I new up a state POCO and manually populate and return that from the dynamic proxy that is returned from the repository? Should I try to use AutoMapper to map the dynamic proxy objects to POCOs? Is there something I'm totally missing here?
I think the answer from Ladislav Mrnka is clear. The Warnings Still apply. Even with this idea below. Becareful what gets picked Up. He just didnt include , if you want to proceed how to easily get data from Object a to object B. That is question at hand really.
Sample solution
See nuget package ValueInjecter (not the only tool that can do this... but very easy to use)
it allows easy copying of One object to another especially with the same properties and types.
( remember the lazy loading / navigation implications).
So vanilla option is :
var PocoObject = new Poco();
PocoObject.InjectFrom(DynamicProxy); // copy contents of DynamicProxy to PocoObject
but check the default behaviour and consider a custom rule
var PocoObject = new Poco();
PocoObject.InjectFrom<CopyRule>(DynamicProxy);
public class CopyRule : ConventionInjection
{
protected override bool Match(ConventionInfo c)
{
bool usePropertry; // return if the property it be included in inject process
usePropertry = c.SourceProp.Name == "Id"; // just an example
//or
// usePropertry = c.SourceProp.Type... == "???"
return usePropertry;
}
}

Can I store enums as strings in EF 5?

We have been using EF CF for a while in our solution. Big fans! Up to this point, we've been using a hack to support enums (creating an extra field on the model; ignore the enum durring mapping; and map the extra field to the column in the db that we would have used). Traditionally we have been storing our enums as strings(varchars) in the DB (makes it nice and readable). Now with enum support in EF 5 (Beta 2) it looks like it only supports mapping enums to int columns in the DB....Can we get EF 5 to store our enums as their string representation.
Where "Type" is an enum of type DocumentType
public enum DocumentType
{
POInvoice,
NonPOInvoice,
Any
}
I tried to map it using:
public class WorkflowMap : EntityTypeConfiguration<Model.Workflow.Workflow>
{
public WorkflowMap()
{
ToTable("Workflow", "Workflow");
...
Property(wf => wf.Type).HasColumnType("varchar");
}
}
I thought was going to be the magic bullet but..
That just throws:
Schema specified is not valid. Errors: (571,12) : error 2019: Member
Mapping specified is not valid. The type
'Dodson.Data.DataAccess.EFRepositories.DocumentType[Nullable=False,DefaultValue=]'
of member 'Type' in type
'Dodson.Data.DataAccess.EFRepositories.Workflow' is not compatible
with
'SqlServer.varchar[Nullable=False,DefaultValue=,MaxLength=8000,Unicode=False,FixedLength=False]'
of member 'Type' in type 'CodeFirstDatabaseSchema.Workflow'.
Your thoughts?
This is currently not possible. Enum in EF has same limitations as enums in CLR - they are just named set of integer values. Check this article for confirmation:
The EF enum type definitions live in conceptual layer. Similarly to
CLR enums the EF enums have underlying type which is one of Edm.SByte,
Edm.Byte, Edm.Int16, Edm.Int32 or Edm.Int64 with Edm.Int32 being the
default underlying type if none has been specified.
I posted article and related suggestion about this problem. If you want to see this feature in the future please vote for the suggestion.
I hit this problem a few weeks ago. The best I could come up with is a bit hacky.
I have a Gender enum on the class Person, and I use data annotations to map the string to the database and ignore the enum.
public class Person
{
public int PersonID { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
[Column("Gender")]
public string GenderString
{
get { return Gender.ToString(); }
private set { Gender = value.ParseEnum<Gender>(); }
}
[NotMapped]
public Gender Gender { get; set; }
}
And the extension method to get the correct enum from the string.
public static class StringExtensions
{
public static T ParseEnum<T>(this string value)
{
return (T)Enum.Parse(typeof(T), value, true);
}
}
See this post for full details - http://nodogmablog.bryanhogan.net/2014/11/saving-enums-as-strings-with-entity-framework/