Is it possible to have Entity framework generate a table, from a model, with the column marked as not null without using the [Required] annotation on the model's property?
Reason:
The object is posted to an api and I check ModelState.IsValid in the controller. The property is supposed to be generated server side and not come from outside, but if I have the property [Required] the ModelState.IsValid is false (in which case I return with a BadRequest(ModelState);).
Can I tell EF to make the column not null in some other way?
I guess another solution would be to expect another object(some sort of DTO) to be sent to the api and then do a mapping. But that object would look exactly the same save for this single property, which makes it seem a bit unnecessary, right?
Use Fluent API and IsRequired method in your DbContext class like this:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<YourEntity>().Property(t => t.YourProperty).IsRequired();
base.OnModelCreating(modelBuilder);
}
If I were you I would not use Entity Framework's entities directly, I would use a DTO first and map it into a EF Entity, why? Because your DTO and EF Entity have not the same responsibility.
DTO : Data transfer object, so just use it to transfer data
EF Entity : it's the model binding to your database.
Related
I would like to use EF core with nullable reference types configured by fluent annotations.
I want to model a one-to-one relationship where SomeEntity has an OtherEntity called Relation, and OtherEntity optionally has a SomeEntity.
Because I don't want to always load the relation, I define OtherEntity as nullable, since it will be null if it's not loaded:
public class SomeEntity {
public virtual OtherEntity? Relation {get;}
}
However, when I use this definition to build a model, OtherEntity becomes nullable in the database definition. That's not my intention: it should be required, in the database, just not necessarily loaded in the code.
How do I model this in such a way that it's clear the value could be null at runtime, but has a database backing store with a column that's not null?
I prefer not to adjust the code of the entity for this purpose, but if there is no other way, that will have to do.
I have the following problem: I have a hierarchy of entities that uses inheritance. I have a two identical fields( the name and type is the same ) in two of the sub-entities. When I try to "Update-Database -Force" on the project EF5 complains that there are there is already a column with name X.
The way EF5 generates the tables is that it actually generates single table and puts there all the fields of the base entity plus the all the fields of the derived entities.
Is there a way to force a different database column name from the property name.
Are there any other solutions( I know it might be architectural problem to duplicate data but making this common will introduce more complex database hierarchy that I don't want to use ).
Thanks:)
This can be done in one of two ways, either using Fluent API or property attributes on your class properties.
[Column("ColumnName")]
public string PropertyName
{
get;
set;
}
See MSDN - ColumnAttribute Class for more details on the column attribute.
Otherwise, use Fluent API. Within your context class-
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<YourClass>().Property(yc => yc.PropertyName).HasColumnName("ColumnName");
See MSDN - HasColumnName extension method for more on this method.
The article linked by Baximilian will be useful in learning more about this.
If I understand you correctly, you need to change column name in DB for field, so you can use ColumnAttribute.
You can find more information here
I am using Entity Framework code-first (non auto generated) and I am trying to map some properties in my OnModelCreating event. Most properties are from a SQL Server table however there is a field I want to include in my model from a view, I have done this and set it as [DatabaseGenerated(DatabaseGeneratedOption.Computed)].
However EF tries to update the view, how do I tell EF to not update my view and treat it as read only, the error I get is...
Cannot update the view or function 'VIEWNAME' because it contains
aggregates, or a DISTINCT or GROUP BY clause, or PIVOT or UNPIVOT
operator
I can see plenty of things to make your view update-able but no to just treat it as read only
UPDATE
After trying a few things I have added [DatabaseGenerated(DatabaseGeneratedOption.Identity)] to the property when defining it in my model and this seems to have done the trick, seems a bit strange though as setting it as Identity doesn't make much sense to me over setting it as computed but seems to be working.
did you try this on your properties?
public virtual string MyProperty { get; internal set; }
this way the entity consumer cannot change it.
I'm looking for some advice. I'm working with EF 5 and I have a generic repository which handles all of the CRUD transactions with the database. This works fine, But i want to add a "Last Gap" safeguard to ensure that the entity is valid before the Data Access Layer attempts changes in the database.
Right before I do something like this :-
DataLayer.Create<TEntity>(entity);
I want to Validate the entity and throw an exception if the validation fails.
What would you guys use as the preferred method?
Using Data Annotations
You can use data annotations directly in your entity. With data annotations, EF will validate the property for you and if it is not valid, an exception will be thrown.
For example, if you want Name to be required, you can do something like:
public class Person
{
[Required]
public string Name { get; set; }
// other members
}
Aside from validation, EF will also set the corresponding column to be not null instead of the default null for strings.
Using the Fluent API
If you don't want to litter your entities with data annotations, you can use the fluent API instead. Following is the equivalent of the above code:
public class MyContext : DbContext
{
public DbSet<Person> People { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
Entity<Person>().Property(p => p.Name).IsRequired();
}
// other members
}
My answer applies to EF Code First and may not apply for other workflows.
Sometimes you have to go to the database to check whether inserting or updating an entity keeps the repository in a valid state - such as when you need to ensure the natural key is unique. That isn't currently handled by a data annotation or the Fluent API, although it has been discussed. See unique constraints in entity framework And this work item.
In the meantime, when you have to go to the database then DbContext will be involved somewhere, and DbContext has an Overridable method called ValidateEntity. See this article: Entity Framework Validation.
I put the code I use in another answer here
And more about how I've structured the validation in MVC here.
I wouldn't do validation at the DAL, but if you do, you might be interested in Validation with the Data Annotation Validators
I just started using the Entity Framework 1.0 recently and believe I am beginning to feel the pains everyone is talking about. I'm trying to use best practices so I have a set of DTO that get mapped to and from my Entities via AutoMapper.
The real catch is when I'm trying to update an object. The first gotcha was that I could not find a way to create a new entity, transfer the data from my DTO, and still have the entity ObjectContext realize that it has been changed. I used the following code:
public VideoDTO UpdateVideo(VideoDTO pVideo)
{
Video video = new Video();
Mapper.Map(pVideo, video);
context.Attach(video); //Successfully attaches
context.ApplyPropertyChanges("Videos", video); // no changes made as far as entity knows b/c it was attached in it's updated state
context.SaveChanges(); //doesn't save the entity
return pVideo;
}
I then figured, perhaps I need to just grab the entity from the database first, attach to the context, call the Map method on Mapper, then call SaveChanges. Here what I did:
public VideoDTO UpdateVideo(VideoDTO pVideo)
{
Video video = context.Videos.Where(v => v.VideoId == pVideo.VideoId).FirstOrDefault();
Mapper.Map(pVideo, video); //Error here: Can't change VideoId value on Video entity
//context.Attach(video);
//context.ApplyPropertyChanges("Videos", video);
context.SaveChanges();
return pVideo;
}
Now we get to the lovely EF issue of not being allowed to change the property, VideoId, because it's used by the EntityKey property on the Video entity. Lovely. I had setup the mappings so that when I mapped from my DTO to an EF Entity, the EntityKey property would get a value. Now I need a way to make an exception to that mapping rule, but have no clue where to begin. I suppose I could create a brand new Mapping rule right in this method and set the EntityKey & VideoId properties to be ignored, but that seems pretty sloppy. Furthermore, I'm not sure a mapping created at this point would stick. If it overrode the initial setup that allowed the DTO to map a value to the EntityKey on the entity, that would backfire in a whole different way.
Anyone have a better idea?
AutoMapper
Your first problem is that as far as I know AutoMapper is not designed to go from DTO->Entity only Entity->DTO. This could have changed recently so I'm not really sure. See this link for more information about what automapper is designed to do: The case for two way mapping
PK Mapping
You say: "Mapping rule right in this method and set the EntityKey & VideoId properties to be ignored, but that seems pretty sloppy"
I don't think thats sloppy at all. You really shouldn't touch a EntityKey/PK after its been persisted and probably should codify its staticness in some way.
Entity Framework
"Now we get to the lovely EF issue of not being allowed to change the property, VideoId, because it's used by the EntityKey property on the Video entity. Lovely."
Lovely? EF is not forcing you to not update your PK. Inside the generated models there is a property change check inside the setter for your keys. The solution would be to change the generated code. Depending on your model volatility this may not be practical but it is an option.
Try mapping to an existing object:
entity = Mapper.Map<MyDTO, NyEntity>(dto, entity);
And keep the Ignore()'s in place.
http://groups.google.com/group/automapper-users/browse_thread/thread/24a90f22323a27bc?fwc=1&pli=1
I'm in the same scenario.
The only solution I got is to Ignore the PK field in the mapping from DTO -> Entity.
Such Rule can be achieved by the following line of code during the Automapper Configuration:
Mapper.CreateMap<MyDTO, MyEntity>().ForMember("EntityPK",r=>r.Ignore());
As far as I know, the only way to get EF works with Detached Entities is mapping the DTO to the Entity you got from DB before the SaveChanges (as you did in the example).
This may help if you want to avoid putting .Ignore()s on every Entity you want to Map.
http://www.prosoftnearshore.com/blog/post/2012/03/14/Using-AutoMapper-to-update-Entity-Framework-properties.aspx
In essence, you'd configure AutoMapper to ignore all Entity properties that are not scalar:
AutoMapper.Mapper.CreateMap<EntityType, EntityType>()
.ForAllMembers(o => {
o.Condition(ctx =>
{
var members = ctx.Parent.SourceType.GetMember(ctx.MemberName); // get the MemberInfo that we are mapping
if (!members.Any())
return false;
return members.First().GetCustomAttributes(typeof(EdmScalarPropertyAttribute), false).Any(); // determine if the Member has the EdmScalar attribute set
});
});
Perhaps some additional work can be added to avoid resetting if the property is a PK (a property in the EdmScalarPropertyAttribute instance (EntityKey == true?) tells you this).
Please be aware that example provided by "Mauricio Morales" will work only if you do not use prefixes. If you use them then you need to change above code slightly in more or less way like this:
Mapper.CreateMap<tempOR_Order, OR_Order>()
.ForMember(m => m.OR_ID, exp => exp.Ignore())
.ForMember(m => m.OR_CU_ID, exp => exp.Ignore())
.ForAllMembers(o => o.Condition(ctx =>
{
var members = ctx.Parent.SourceType.GetMember(ctx.MemberName); // get the MemberInfo that we are mapping
if (!members.Any())
{
members = ctx.Parent.SourceType.GetMember("temp" + ctx.MemberName);
if (!members.Any())
return false;
}
return members.First().GetCustomAttributes(typeof(EdmScalarPropertyAttribute), false).Any(); // determine if the Member has the EdmScalar attribute set
}));
That is, you need to include additional checks inside if (!members.Any()) statement. Without this, function return false and mapping will not work.