Generate money type fields using code first EF CTP5 - entity-framework

In this blog post: EF4 Code First Control Unicode and Decimal Precision, Scale with Attributes, Dane Morgridge used attributes to control the creation of different types on your database.
...And I found this pretty unique BTW!!!
How do I generate money type fields in my resulting database using code first API of EF CTP5, if is possible to do it from your model, using conventions or attributes?
Sorry about my English is not my main language.
Thanks in advance.

For example, consider this Invoice class:
public class Invoice
{
public int InvoiceId { get; set; }
public decimal Amount { get; set; }
}
You can do it with fluent API:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Invoice>()
.Property(i => i.Amount)
.HasColumnType("Money");
}
Or you can do it with Data Annotations:
public class Invoice
{
public int InvoiceId { get; set; }
[Column(TypeName="Money")]
public decimal Amount { get; set; }
}

using System.Data.Entity.ModelConfiguration.Configuration.Properties.Primitive;
public class MoneyAttribute : Attribute { }
public class MoneyAttributeConvention : AttributeConfigurationConvention<PropertyInfo, DecimalPropertyConfiguration, MoneyAttribute> {
public override void Apply(PropertyInfo memberInfo, DecimalPropertyConfiguration configuration, MoneyAttribute attribute) {
configuration.ColumnType = "money";
}
}
then you use like that
[Money]
public decimal Value { get; set; }

Related

Is there a way to have EF Core populate navigation properties before the change tracker snapshots values?

I have an order model in my core with a collection of (abstract base) OrderLines which can be either a NoteLine or an ItemLine. Each ItemLine has various pricing details relevant to that specific line.
public class Order : IEntity<int>
{
public int Id { get; private set; }
protected ICollection<OrderLine> _Lines;
public IEnumerable<OrderLine> Lines => _Lines.AsEnumerable();
public decimal TotalSellEx
{
get => _Lines.OfType<ItemLine>().Sum(l => l.TotalSellEx);
protected set { }
}
}
public class NoteLine
{
public string Note { get; protected set; }
}
public class ItemLine
{
public int StockId { get; protected set; }
public decimal TotalSellEx => ItemSellEx * Quantity;
public decimal ItemSellEx { get; protected set; }
public decimal GrossProfit { get; protected set; }
public int Quantity { get; protected set; }
}
public abstract class OrderLine
{
public decimal LineNumber { get; protected set; }
}
public class OrderConfiguration : EntityConfiguration<Order, int>
{
public override void Configure(EntityTypeBuilder<Statement> builder)
{
base.Configure(builder);
builder.HasMany(o => o.Lines)
.WithOne(o => o.Statement);
builder.Navigation(o => o.Lines)
.AutoInclude();
}
}
My Order model then uses a getter only property to keep a rolling sum of the total values as the list is manipulated by various functions and is successfully persisted to the database due to the empty setter to get around EF Core's need for a setter.
The problem occurs when I pull the record out of the database and change tracker kicks in. It seems to be that the snapshot of this model is created before navigation properties are populated so the total value is always 0 in the change tracker.
This isn't a big problem until the total value is modified in such a way that it becomes 0 properly. In which case EF Core doesn't see a change and doesn't populate the UPDATE statement with this column. At this point any projections containing this property are wrong, showing the previous value before it was set back to 0.
For the record, it always seems that once the object is retrieved the lines are all there, just not during change tracking snapshotting.
Is there a way to get around this behaviour? Or do I have to settle for bandaid work arounds?

Multiple Common Fields CreatedOn and CreatedBy in every table of a database. How it can be without repeating for every table

Scenerio:
public class Department
{
public int DepartmentId { get; set; }
public string DepartmentName { get; set; }
public string Description { get; set; }
public DateTime CreatedOn {get; set; }
public string CreatedBy {get; set; }
}
public class TestItem
{
public int TestItemId { get; set; }
public string TestItemName { get; set; }
public Department Department { get; set; }
public int DepartmentId { get; set; }
public DateTime CreatedOn {get; set; }
public string CreatedBy {get; set; }
}
public class Patient
{
public int PatientId { get; set; }
public string PatientName { get; set; }
public DateTime CreatedOn {get; set; }
public string CreatedBy {get; set; }
}
the problem is that, every time I create a table I have to add those two columns repeatedly.
But I want like this-
public class EntryLog
{
public int EntryLogId { get; set; }
public DateTime CreatedOn {get; set; }
public string CreatedBy {get; set; }
}
public class Department
{
public int DepartmentId { get; set; }
public string DepartmentName { get; set; }
public string Description { get; set; }
public EntryLog EntryLog { get; set; }
public int EntryLogId { get; set; }
}
and so on...
class A { .. }
class B { .. }
But its creating problem [showing conflicts error with other table's foreign key] while creating a row for a Department or a Patient.
In EF core, there is Table Per Hierarchy (TPH) but in that case every table will be merged into a single table. But that doesn't give me any solution.
looking forward to expert's suggestion...
The bottom line is: use EntryLog as a base type and don't tell EF about it. It's easy enough to keep EF-core oblivious of the base type: only register the derived types. Doing so, EF-core will map your subtypes to their own tables, just as if they didn't have a common type.
Now EntryLog will no longer need an Id, and it should be abstract:
public abstract class EntryLog
{
public DateTime CreatedOnUtc { get; set; }
public string CreatedBy { get; set; }
}
Whether this is enough depends on your specific requirements. There are several possibilities.
1. No additional configuration
If you're happy with the default conventions EF will apply to the common properties, your done. CreatedOnUtc will be mapped to a DateTime2 column (in Sql Server) and CreatedBy to an nvarchar(max) column in each table for an EntryLog entity.
However, if you do need custom configurations --for example if you want to map CreatedBy to an nvarchar(50) column-- additional mapping instructions should be applied. And of course you still want to do the mapping of the common properties only once --which would also happen if you did map the base type in a TPH scheme. How to do that?
2. Data annotations in the base type
The easiest option is to add data annotations:
public abstract class EntryLog
{
public DateTime CreatedOnUtc { get; set; }
[MaxLength(50)]
public string CreatedBy { get; set; }
}
And that's all.
But there are dev teams that don't want to use data annotations for mapping instructions. Also, EF's fluent mappings offer more options than data annotations do. If data annotations don't fit the bill for whatever reason, fluent configurations must be applied. But still, you only want to configure the common properties only once. A viable way to achieve that is to use IEntityTypeConfigurations for each EntryLog and let each concrete configuration derive from a base class. This offers two more options.
3. The base class contains regular properties
Option 4 will make clear why I talk about "regular properties" here. This is what it looks like:
abstract class EntryLogConfiguration
{
public void ConfigureBase<TEntity>(EntityTypeBuilder<TEntity> builder)
where TEntity : EntryLog
{
// Just an example of how to configure a base property.
builder.Property(e => e.CreatedBy).HasMaxLength(50);
}
}
class DepartmentConfiguration : EntryLogConfiguration,
IEntityTypeConfiguration<Department>
{
public void Configure(EntityTypeBuilder<Department> builder)
{
builder.Property(p => p.DepartmentName).HasMaxLength(100);
ConfigureBase(builder);
}
}
And in the context:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.ApplyConfiguration(new DepartmentConfiguration());
}
4. Using shadow properties
Shadow properties is a new feature of EF-core.
Shadow properties are properties that are not defined in your .NET entity class but are defined for that entity type in the EF Core model. The value and state of these properties is maintained purely in the Change Tracker.
Let's suppose you want to have CreatedBy as a class property (because you want to show it in a UI) but only need CreatedOnUtc as a property that's set in the background and that shouldn't be exposed. Now EntryLog will look like this:
public abstract class EntryLog
{
public string CreatedBy { get; set; }
}
So the property CreatedOnUtc is gone. It has been moved to the base configuration as shadow property:
abstract class EntryLogConfiguration
{
public void ConfigureBase<TEntity>(EntityTypeBuilder<TEntity> builder)
where TEntity : EntryLog
{
builder.Property(e => e.CreatedBy).HasMaxLength(50);
builder.Property<DateTime>("CreatedOnUtc");
}
}
Now you can't set CreatedOnUtc directly, only through EF's change tracker. The best place to do that is in an override of SaveChanges in the context:
public override int SaveChanges()
{
foreach (var entry in ChangeTracker.Entries<EntryLog>())
{
entry.Property<DateTime>("UpdatedOnUtc").CurrentValue = DateTime.UtcNow;
}
return base.SaveChanges();
}
Of course, if UpdatedOnUtc was a regular property, this override would also come in handy, but you could just do
entry.Entity.CreatedOnUtc = DateTime.UtcNow;
I hope this will give you enough food for thought to figure out which option suits you best.

Entity Framework and Models with Simple Arrays

This is my model class.
public class Lead
{
private readonly ObservableCollection<String> m_tags = new ObservableCollection<string>();
public int LeadId { get; set; }
public string Title { get; set; }
public ObservableCollection<String> Tags { get { return m_tags; } }
}
Does Entity Framework offer a way to represent this using either Model-First or Code-First?
EDIT: I'm looking for a way to do this without changing the public API of the model. The fact that there is some sort of Tags table shouldn't be visible to the downstream developer.
Since your model has to be represented in a relational way, you can only use primitive types (that have an equivalent in a SQL DB) or other entities within a entity definition - that means the tags are represented by their own entity. In your case it would be something like this using Code first approach:
public class Lead
{
public int LeadId { get; set; }
public string Name { get; set; }
public virtual ICollection<Tag> Tags { get; set; }
}
public class Tag
{
public int TagId { get; set; }
public string Name { get; set; }
}
public class SomeContext : DbContext
{
public DbSet<Lead> Leads { get; set; }
public DbSet<Tag> Tags { get; set; }
}
This (by default) will be represented in the database as a table Leads, a table Tags, and a relationship table LeadTags that only contains {LeadId, TagId} pairs.

in entity framework code first, how to use KeyAttribute on multiple columns

I'm creating a POCO model to use with entity framework code first CTP5. I'm using the decoration to make a property map to a PK column. But how can I define a PK on more then one column, and specifically, how can I control order of the columns in the index? Is it a result of the order of properties in the class?
Thanks!
NOTE:
As of 2019 this answer became non-valid for later EntityFramework versions.
You can specify the column order in the attributes, for instance:
public class MyEntity
{
[Key, Column(Order=0)]
public int MyFirstKeyProperty { get; set; }
[Key, Column(Order=1)]
public int MySecondKeyProperty { get; set; }
[Key, Column(Order=2)]
public string MyThirdKeyProperty { get; set; }
// other properties
}
If you are using the Find method of a DbSet you must take this order for the key parameters into account.
To complete the correct answer submitted by Slauma, you can use the HasKey method to specify an order for composite primary keys as well:
public class User
{
public int UserId { get; set; }
public string Username { get; set; }
}
public class Ctp5Context : DbContext
{
public DbSet<User> Users { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<User>().HasKey(u => new
{
u.UserId,
u.Username
});
}
}
If, like me, you prefer to use a configuration file you can do that in this way (based on Manavi's example):
public class User
{
public int UserId { get; set; }
public string Username { get; set; }
}
public class UserConfiguration : EntityTypeConfiguration<User>
{
public UserConfiguration()
{
ToTable("Users");
HasKey(x => new {x.UserId, x.Username});
}
}
Obviously you have to add the configuration file to your context:
public class Ctp5Context : DbContext
{
public DbSet<User> Users { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Configurations.Add(new UserConfiguration());
}
}
Use as a anonymous object:
modelBuilder.Entity<UserExamAttemptQuestion>().ToTable("Users").HasKey(o => new { o.UserId, o.Username });

Relationship Mapping in EF4 code-only CTP (when using inheritance?)

I'm producing a simple composite patterned entity model using EF4 w/ the code-first CTP feature:
public abstract partial class CacheEntity
{
[Key]public string Hash { get; set; }
public string Creator { get; set; }
public int EntityType { get; set; }
public string Name { get; set; }
public string Predecessor { get; set; }
public DateTime DateTimeCreated { get; set; }
public virtual ICollection<CacheReference> References { get; set; }
}
public partial class CacheBlob : CacheEntity
{
public byte[] Content { get; set; }
}
public partial class CacheCollection : CacheEntity
{
public virtual ICollection<CacheEntity> Children { get; set; }
}
public class CacheReference
{
public string Hash { get; set; }
[Key]public string Reference { get; set; }
public virtual CacheEntity Entity { get; set; }
}
public class CacheEntities : DbContext
{
public DbSet<CacheEntity> Entities { get; set; }
public DbSet<CacheReference> References { get; set; }
}
Before I split out the primitive/collection derived classes it all worked nicely, but now I get this:
Unable to determine the principal end of the 'Cache.DataAccess.CacheEntity_References'
relationship. Multiple added entities may have the same primary key.
I figured that it may have been getting confused, so I thought I'd spell it out explicitly using the fluent interface, rather than the DataAnnotation attributes. Here's what I think defines the relationship properly:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<CacheEntity>().HasKey(ce => ce.Hash);
modelBuilder.Entity<CacheEntity>().HasOptional(ce => ce.References).WithMany();
modelBuilder.Entity<CacheReference>().HasKey(ce => ce.Reference);
modelBuilder.Entity<CacheReference>().HasRequired(cr => cr.Entity).WithOptional();
}
But I must be wrong, because now I get this:
Entities in 'CacheEntities.CacheReferenceSet' participate in the
'CacheReference_Entity' relationship. 0 related 'Entity' were found. 1 'Entity' is expected.
Various other ways of using the fluent API yield different errors, but nothing succeeds, so I am beginning to wonder whether these need to be done differently when I am using inheritance.
Any clues, links, ideas, guidance would be very welcome.
using the MapHierarchy works for me:
protected override void OnModelCreating(ModelBuilder builder){
builder.Entity<CacheBlob>().HasKey(b=> b.Hash).MapHierarchy();
}
As an example.
Further reference : http://blogs.msdn.com/b/efdesign/archive/2009/10/12/code-only-further-enhancements.aspx