How to automatically set maxlengh property for textbox from EF? - entity-framework

I am using normal helper EditFor to bind data to html controls.
For completeness, here a example:
#Html.EditorFor(model => model.Description, new { htmlAttributes = new { #maxlength= 100, #class = "form-control" } })
To set maxlength for string fields, i need to explicitly set the attribute in every view that uses the same table field and there are many views and strings value in the data model.
Doing this in every page is error prone. Changes is size will break the app if a place is forgotten.
How to pass the length directly from EF Model?

The easiest option is to add the [MaxLength(50)] attribute to the model property. For example:
public class SomeModel
{
[MaxLength(50)]
public string SomeProperty { get; set; }
}
You can then omit the maxlength property from the call to #Html.EditorFor() and it will be taken from the model metadata.

You can use the Fluent API to configure a maximum length for a property. In this example, targeting SQL Server this would result in the nvarchar(500) data type being used.
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Test>()
.Property(b => b.Description)
.HasMaxLength(500);
}
Or You can use the Data Annotations to configure a maximum length for a property.
public class Test
{
[MaxLength(500)]
public string Description{ get; set; }
}

Related

Have specific property configuration for all types that implement an interface except for one

I have a number of Types that inherit from the Interface 'IEventReportElement', which exposes the property 'IdEventReport':
public interface IEventReportElement
{
long Id { get; set; }
long? IdEventReport { get; set; }
}
This is a nullable property, as I'm not always able to fill it out properly right away, but should be not nullable in the database.
Thats why I have added the line
modelBuilder.Types<IEventReportElement>().Configure(x=>x.Property(y=>y.IdEventReport).IsRequired());
to my OnModelCreating method in the DbContext.
However, the Type 'Position' has to implement this interface, but should NOT have the column for property 'IdEventReport' in the database, but instead a column for the property 'IdParent' it exposes.
public class Position : BOBase, IEventReportElement
{
public long? IdEventReport
{
get { return IdParent; }
set { IdParent = value; }
}
public long? IdParent { get; set; }
}
and the section in the modelBuilder
modelBuilder.Entity<Position>().Property(x => x.IdParent).IsRequired();
modelBuilder.Entity<Position>().Ignore(x => x.IdEventReport);
However, this throws an exception already when trying to Create the database:
System.InvalidOperationException: The property 'IdEventReport' is not a declared property on type 'Position'. Verify that the property has not been explicitly excluded from the model by using the Ignore method or NotMappedAttribute data annotation. Make sure that it is a valid primitive property.
Though this may be valid, is it not possible to override the given Type configuration for a specific type? Do I have to add the line .IsRequired() to every other type that implements this interface, or is there another way to overcome this?
I did find a solution, however it's a not so nice one. I did it by modifying the line of the type configuration to
modelBuilder.Types<IEventReportElement>().Where(x=>x.Name!="Position").Configure(x=>x.Property(y=>y.IdEventReport).IsRequired());
If you just want that the column has a different name in the database, use HasColumnName.
For access to IdParent in the C# model, use [NotMapped] to tell EF to ignore this property when creating the DB.
public class Position : BOBase, IEventReportElement {
public long? IdEventReport {get; set; }
[NotMapped]
public long? IdParent {
get { return IdEventReport ; }
set { IdEventReport = value; }
}
}
modelBuilder.Entity<Position>().Property(x => x.IdEventReport).HasColumnName("IdParent");
As a side note: why are you implementing an interface that you don't want to use? Maybe you can split the interface in smaller parts and only implement what you are going to use.

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");

Have a custom Setter on property for EF Code First model entity

Is it possible to override or add code to setter of property for entity model object in EF Code First approach.
e.g.
public class Contact
{
[Key]
public int Id { get; private set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string JobTitle
{
get;
set { // eg. proper case the job title }
}
}
I had tried having a public property marked NotMapped and this set/get to private/protected property that is. But it seems that the property has to public to be created in table.
You can write the logic in there if you want, just transform the property into a non-automatic one and perform the checks as you would do with a normal property.
private string jobTitle;
public string JobTitle
{
get { return jobTitle; }
set
{
// do your fancy stuff or just jobTitle = value
}
}
Remember that if you change the value from db inside your setter it will probably be saved that way later on after you perform SaveChanges() on the context.
Description
You can ignore the propertie using the ModelBuilder and .Ignore(...)
.Ignore(...) Excludes a property from the model so that it will not be mapped to the database.
Sample
public class MyDbContext : DbContext
{
public DbSet<Contact> Contact { get; set; }
// other DbSet's
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<Contact>().Ignore(x => x.JobTitle);
}
}
More Information
EF Features: Fluent API Samples
I did something slightly different.
In your example I would change the mapping file so that the getter and setter on the property that is mapped to the database to be private and lowercase just as dmusial showed. Then I created a property that was NOT mapped in the edmx file as show here (Note: While I usually would make member fields _jobTitle, I'm using the code generation and starting with an _ is not allowed in EF 5.x).
///<summary>
/// Private member mapped in .edmx file
/// Something like:
/// <Property Name="jobTitle" Type="String" MaxLength="Max" FixedLength="false"
/// a:SetterAccess="Private" a:GetterAccess="Private"
/// xmlns:a="http://schemas.microsoft.com/ado/2006/04/codegeneration" />
///</summary>
private string jobTitle { get; set; }
///<summary>
/// Publicly visible property that now contains your logic.
///</summary>
public string JobTitle
{
get { return jobTitle; }
set { jobTitle = SetProperCase(value); }
}
Now when SaveChanges is called it should save the jobTitle property into the column to which it is mapped in your edmx file.

EF Code First Readonly column

I am using EF Code first with database first approach.
"with Database.SetInitializer(null);"
My table has two columns createddate and amendddate. They are managed by SQL Server using triggers. The idea is that when data entry happens then these columns gets data via triggers.
Now What I want to do is to make this read only from EF Code first point of view. I.e. I want to be able to see the createddate and ameneded dates from my app but I dont want to amend these data.
I have tried using private modifiers on setter but no luck.When I try to add new data to the table it tried to enter DateTime.Max date to the database which throws error from SQL server.
Any idea?
You cannot use private modifiers because EF itself needs to set your properties when it is loading your entity and Code First can only do this when a property has public setter (in contrast to EDMX where private setters are possible (1), (2)).
What you need to do is mark your for CreatedDate with DatabaseGeneratedOption.Identity and your AmendDate with DatabaseGeneratedOption.Computed. That will allow EF to correctly load data from the database, reload data after insert or update so that entity is up to date in your application and at the same time it will not allow you to change the value in the application because the value set in the application will never be passed to the database. From an object oriented perspective it is not a very nice solution but from the functionality perspective it is exactly what you want.
You can do it either with data annotations:
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public DateTime CreatedDate { get; set; }
[DatabaseGenerated(DatabaseGeneratedOption.Computed)]
public DateTime AmendDate { get; set; }
Or with fluent API in OnModelCreating override in your derived context:
modelBuilder.Entity<YourEntity>()
.Property(e => e.CreatedDate)
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
modelBuilder.Entity<YourEntity>()
.Property(e => e.AmendDate)
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.Computed);
EF core 1.1 or later versions yes you can use read only property in poco classes. What you need to do is using backing-field.
public class Blog
{
private string _validatedUrl;
public int BlogId { get; set; }
public string Url
{
get { return _validatedUrl; }
}
public void SetUrl(string url)
{
using (var client = new HttpClient())
{
var response = client.GetAsync(url).Result;
response.EnsureSuccessStatusCode();
}
_validatedUrl = url;
}
}
class MyContext : DbContext
{
public DbSet Blogs { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Blog>()
.Property(b => b.Url)
.HasField("_validatedUrl");
}
}
and fluent api...
modelBuilder.Entity<Blog>()
.Property(b => b.Url)
.HasField("_validatedUrl")
.UsePropertyAccessMode(PropertyAccessMode.Field);
Take a look here..

How do I find the output model type in a behavior?

With FubuMVC, I'm not sure what the best way is to determine the current action's output model type. I see different objects that I could get the current request's URL from. But that doesn't lead to a very good solution.
What's the easiest way to get the current action's output model type from the behavior?
If this isn't a good practice, what's a better way?
First, I'm assuming you've already got your settings object(s) set up in StructureMap and have the ISettingsProvider stuff already wired up.
The best, simplest thing to do would be just to pull the settings in the view, like this:
<%: Get<YourSettingsObject>().SomeSettingProperty %>
If you insist on having these be a property on your output model, then continue reading:
Let's say you had a settings object like this:
public class OutputModelSettings
{
public string FavoriteAnimalName { get; set; }
public string BestSimpsonsCharacter { get; set; }
}
Then you had an output model like this:
public class OutputModelWithSettings
{
public string SomeOtherProperty { get; set; }
public OutputModelSettings Settings { get; set; }
}
You'll need to do a few things:
Wire up StructureMap so that it will do setter injection for Settings objects (so it will automatically inject the OutputModelSettings into your output model's "Settings" property.
Set up a setter injection policy in your StructureMap initialization code (a Registry, Global ASAX, your Bootstrapper, etc -- wherever you set up your container).
x.SetAllProperties(s => s.Matching(p => p.Name.EndsWith("Settings")));
Create your behavior to call StructureMap's "BuildUp()" on the output model to trigger the setter injection. The behavior will be an open type (i.e. on the end) so that it can support any kind of output model
public class OutputModelSettingBehavior<TOutputModel> : BasicBehavior
where TOutputModel : class
{
private readonly IFubuRequest _request;
private readonly IContainer _container;
public OutputModelSettingBehavior(IFubuRequest request, IContainer container)
: base(PartialBehavior.Executes)
{
_request = request;
_container = container;
}
protected override DoNext performInvoke()
{
BindSettingsProperties();
return DoNext.Continue;
}
public void BindSettingsProperties()
{
var viewModel = _request.Find<TOutputModel>().First();
_container.BuildUp(viewModel);
}
}
Create a convention to wire up the behavior
public class OutputModelSettingBehaviorConfiguration : IConfigurationAction
{
public void Configure(BehaviorGraph graph)
{
graph.Actions()
.Where(x => x.HasOutput &&
x.OutputType().GetProperties()
.Any(p => p.Name.EndsWith("Settings")))
.Each(x => x.AddAfter(new Wrapper(
typeof (OutputModelSettingBehavior<>)
.MakeGenericType(x.OutputType()))));
}
}
Wire the convention into your FubuRegistry after the Routes section:
ApplyConvention<OutputModelSettingBehaviorConfiguration>();
In your view, use the new settings object:
<%: Model.Settings.BestSimpsonsCharacter %>
NOTE: I have committed this as a working sample in the FubuMVC.HelloWorld project in the Fubu source. See this commit: https://github.com/DarthFubuMVC/fubumvc/commit/2e7ea30391eac0053300ec0f6f63136503b16cca