entityframework Inherited classes in single table can not use timestamp? - entity-framework

I want to create a TimeStamp field in Inherited class like this:
[Table("TABLE_A")]
public class A
{
public int ID {get;set;}
public string Name {get;set;}
}
[Table("TABLE_B")]
public class B : A
{
public string Address {get;set;}
[TimeStamp]
public byte[] RowVersion {get;set;}
}
but failed, how can I do here ?

You will see error
Type 'B' defines new concurrency requirements that are not allowed for
subtypes of base EntitySet types.
That means exactly what error says. Entity Framework do not support concurrency checks in derived types. You will see same error if you'll add simple concurrency check instead of timestamp:
[Table("TABLE_B")]
public class B : A
{
[ConcurrencyCheck]
public string Address { get; set; }
}
If you will move concurrency checking to base class, then it will work, but only on base type. If you need checking to be performed on derived type, I think you should use Stored Procedure for updating entity.

Related

Unable to cast the type 'Claim' to type 'ClaimDetail'. LINQ to Entities only supports casting EDM primitive or enumeration types

I have a problem with an EF6 and LINQ to Entities method inasmuch as I cannot cast from one class, Claim, to a derived class, ClaimDetail. I am certain that this cast would be valid but I don't know fiddle with the syntax to get the cast to work.
The relevant portions of the model look like this:
// Claim.cs
public class Claim
{
public int Id { get; set; }
// ..other properties
}
and
// ClaimDetail.cs
public class ClaimDetail : Claim
{
public string ClaimRef { get; set; }
// ..other properties
}
I have another class, Request, that looks like this:
// Request.cs
public class Request
{
public Claim Claim { get; set; }
// ..other properties
}
These classes form a part of the context, like this:
// Context.cs
public DbSet<ClaimDetail> Claims { get; set; }
public DbSet<Request> Requests { get; set; }
Now, I would like to sort a LINQ query of Requests based on a property of ClaimDetail. I have this:
sorted = intermediate.OrderBy(r => ((ClaimDetail)r.Claim).ClaimRef);
where intermediate is an IQueryable<Request>. However, on trying to materialize this query, I receive the following message:
Unable to cast the type 'Claim' to type 'ClaimDetail'. LINQ to Entities only supports casting EDM primitive or enumeration types.
How can I do this, without resorting to calling ToList() on the intermediate results? That would be far too expensive.

Cannot convert IQueryable<T> AsEnumerable because T has a Guid property

I have the following EF class:
class Product
{
public Guid ProductGuid { get; set; }
public string ProductName { get; set; }
}
derived from a DB class where ProductGuid is a uniqueidentifier and ProductName is a nvarchar.
Consider productContext as the context:
var products = productContext.Products;
productList = products.ToList();
OR
productList = products.AsEnumerable();
The first instruction is executed correctly the second (both) launches an exception at runtime (it compiles correctly):
Unable to cast the type 'System.Guid' to type 'System.Object'. LINQ to
Entities only supports casting Entity Data Model primitive types.
I tried everything it does not work. I have other tables with Guid field but it never launches such exception. What can be the cause?
Do you really need to use the GUID type in that property? Wouldn't string do it for you anyway?
try replacing GUID. use String instead.

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/

Overriding EF CodeFirst Generated Database

I have a C# project that uses the EF CodeFirst approach. My problem is how EF is interpreting my classes and generating the database tables. EF is inferring too many things and my resulting db is not the way I would like. Specifically, it is generating additional id columns in one of my mapping classes.
Here are my POCO classes:
public partial class Attribute
{
public int Id {get;set;}
public string Name {get;set;}
public virtual ICollection<EntityAttribute> EntityAttributes {get;set;}
}
public partial class Grant
{
public int Id {get;set;}
public string Name {get;set;}
public virtual ICollection<EntityAttribute> EntityAttributes {get;set;}
}
public partial class Donor
{
public int Id {get;set;}
public string Name {get;set;}
public virtual ICollection<EntityAttribute> EntityAttributes {get;set;}
}
public enum EntityTypeEnum
{
Grant = 1,
Donor = 2
}
public partial class EntityAttribute
{
public int Id {get;set;}
public int EntityId {get;set;}
public int AttributeId {get;set;}
public int EntityTypeId {get;set;}
public EntityTypeEnum EntityType
{
get{return (EntityTypeEnum)this.EntityTypeId;}
set{this.EntityTypeId = (int)value;}
}
public virtual Grant Grant {get;set;}
public virtual Donor Donor {get;set;}
}
My mapping classes are typical but here is the EntityAttributeMap class:
public partial class EntityAttributeMap : EntityTypeConfiguration<EntityAttribute>
{
public EntityAttributeMap()
{
this.ToTable("EntityAttribute");
this.HasKey(ea => ea.Id);
this.Property(ea => ea.EntityTypeId).IsRequired();
this.Ignore(ea => ea.EntityType);
this.HasRequired(ea => ea.Grant)
.WithMany(g => g.EntityAttributes)
.HasForeignKey(ea => ea.EntityId);
this.HasRequired(ea => ea.Donor)
.WithMany(d => d.EntityAttributes)
.HasForeignKey(ea => ea.EntityId);
this.HasRequired(ea => ea.Attribute)
.WithMany(a => a.EntityAttributes)
.HasForeignKey(ea => ea.AttributeId)
}
}
All of my unit tests perform as expected. However, the table EntityAttribute gets rendered with DonorId and GrantId columns. I don't want this as I actually have dozens of other "EntityTypes" that will be used for this scenario. That is why I chose the EntityTypeEnum class.
What am I doing wrong? Or is there another way I should be mapping these so EF handles things the way I want. Thanks.
The EF doesn't support enums at all, as of V4 CTP 5. They might be included in the next release.
Having said that, the schema looks (to me; it's not clear from your post, and your intentions may be different) too close to an EAV for my comfort. For the usual reasons (Google it) I dislike these, and wouldn't want that sort of model even with enum support in the EF.
Why not map to another entity type instead of an enum?
If you ask a question in the form of "Here are my business needs; what is the best schema for this?" you may get a better answer.

DataAnnotations MetadataType Class Ignores Base Class Properties

I've run into a bit of a wall in trying to use the .NET DataAnnotations feature to provide simple validations in a derived class. I am marking up my class with the standard annotations included in .NET 4 (from the System.ComponentModel.DataAnnotations namespace), then using the MS Enterprise Library v5 Validation Block to process the rules.
I have a number of objects derived from a common base class, which contains properties common to all of my objects. For validation purposes, I may have different rules for the various classes derived from this class.
Here's a simplified example:
public abstract class PersonBase
{
public int Id { get; set; }
public string Name { get; set; }
}
[MetadataType(typeof(CustomerMD))]
public class Customer : PersonBase
{
}
[MetadataType(typeof(ManagerMD))]
public class Manager : PersonBase
{
}
public class CustomerMD
{
[Required]
[StringLength(20, ErrorMessage="Customer names may not be longer than 20 characters.")]
public object Name { get; set; }
}
public class ManagerMD
{
[Required]
[StringLength(30, ErrorMessage = "Manager names may not be longer than 30 characters.")]
public object Name { get; set; }
}
// calling code
var invalidCustomer = new Customer {Id=1, Name=string.Empty};
var valFactory = EnterpriseLibraryContainer.Current.GetInstance<ValidatorFactory>();
var customerValidator = valFactory.CreateValidator<Customer>();
var validationResults = customerValidator.Validate(invalidCustomer);
// validationResults.IsValid should equal False, but actually equals True.
I have found that I can get the expected validation results if I push the annotations down to the base class, but then I lose the ability to fulfill different requirements for different types. Also, if I put class-specific properties on a derived class and provide metadata for these properties, I get results, but only for these properties, not the properties from the base class.
I haven't yet tried using the EntLib provided validation attributes; I'd prefer to keep the library this lives in free of dependencies from outside the core framework, if at all possible.
Am I missing something, or am I just out of luck here?
I think I have a workable solution for this.
It appears that the Metadata class will not provide validation of properties belonging to the superclass of the target object. In order to get Metadata to work with this, I needed to mark the superclass properties as virtual, then provide overrides for the properties that I wanted to validate.
Example (see question above for original example):
public abstract class PersonBase
{
public virtual int Id { get; set; }
public virtual string Name { get; set; }
}
[MetadataType(typeof(CustomerMD))]
partial class Customer : PersonBase
{
public override string Name
{
get
{
return base.Name;
}
set
{
base.Name = value;
}
}
}
With the override in place, the validator works as expected. It's a little more work, but it will get the job done.
I also tried adding annotations to the base class as fallback default rules; this allows me to have a base set of rules and override them as needed on a case by case basis. Looking good.
I run into the same issue and couldn't make it annotate a base class with Attributes using MethadataType. Like Scroll Lock I did the overriding part for base class virtual properties. On top of it I made "shadowing" for the none virtual properties.
public class BaseClass
{
public virtual int Id {get;set;}
public string Name {get;set;}
}
public class DerivedClass
{
[SomeAttribute]
public ovveride int Id {get{ return base.Id;} set{ base.Id = value;}}
[SomeAttribute]
public new string Name {get{ return base.Name;} set{ base.Name = value;}}
}