Combine columns in entity framework into one column with the edmx designer - entity-framework

I'm using EntityFramework 5 EDMX designer and would like to combine the first & last name of a person into a single field value (name, for instance) on the entity.
I thought in previous versions there was a way to do this, but I don't see anything available to do what I need to do.
Is this still possible?

Unless I'm not understanding your question, I believe I've done that with a partial class that resembles something like the following:
public partial class person
{
public string name {
get
{
return firstname + " " + lastname;
}
set{ }
}
}

No it is not possible. You can create model defined function and use it in queries but it will still not be part of your entity. If your entity is read only you can create database view with combined column and map it instead of the table - it shows also main reason why combining columns into single property is not such easy task. Automatic concatenating during reading is easy but automatic decomposing to save correct value into correct column is hard and error prone.
If you need combined property for anything else than querying you can simply create another partial part of your entity class and add your own computed property. If you need the combined property for querying use the model defined function.

The way I do this is through a Computed Column as explained here:
How to make a computed column nullable in SQL Server
If you use a computed column you'll be able to use such a column in your LINQ queries. For example:
var users = Database.Users.Where(u => u.FullName.ToLower().Contains("string"));
You won't get errors like "not supported in LINQ to Entities" because this property is really a part of your model object. All the heavy lifting occurs on the database side.
Of course you could place a FullName property in a partial class and use it.
public string FullName
{
get { return string.Format("{0} {1}", FirstName, LastName); }
}
In this case, you'll have to call .ToList() first ( Database.Users.ToList(); ) to be able to use this property in LINQ queries. .ToList() will hydrate/bring all your Users to memory. This is not desirable!
You can also try the FullName property implementation that's described here: Calculated Columns in Entity Framework Code First Migrations

Related

Entity Framework MapToStoredProcedures - Ignore Parameters

We have a db table that has the following columns.
WidgetId (PK)
WidgetName
WidgetCreatedOn
WidgetLastUpdatedOn
We have stored procedures that handle the update/delete/insert on the Widget table.
The Insert stored proc takes just the WidgetName as the parameter e.g.
exec Widget_Insert #WidgetName='Foo Widget'
Then the stored procedure puts the dates in for the WidgetCreatedOn WidgetLastUpdatedOn itself.
The Widget object has the same properties as the table e.g.
WidgetId (Key)
WidgetName
WidgetCreatedOn
WidgetLastUpdatedOn
Is it possible to tell the MapToStoredProcedures to ignore specific properties e.g.
modelBuilder.Entity<Widget>()
.MapToStoredProcedures(s =>
s.Insert(i => i.HasName("Widget_Insert")
.Parameter(a => a.WidgetName, "WidgetName")
.Parameter(a => a.WidgetCreatedOn, **dont map it**)
.Parameter(a => a.WidgetLastUpdatedOn, **dont map it**)));
We are doing Code-First
While there might be a way to manually change the MapToStoredProcedures configuration to do this, I have not uncovered it yet. Having said that, there is a way to accomplish this which I assume is how EF expects you to do things.
In your model mapping, specifying a DatabaseGeneratedOption of Identity or Computed will prevent that property from being sent to the insert proc.
If you think about it, this makes some sense. An insert proc will take as much information from the model as possible to do the insert. But an Identity/Computed property is one for which you're saying the DB will provide the data instead so it won't look to the model for that data.
A couple of things to note with this approach. EF will expect those Identity/Computed fields to come back from the proc so you'll need a select after the insert (filtering on SCOPE_IDENTITY() in sql server). EF also assumes that Identity fields won't come back as null, so those have to be Computed even if you don't intend them to be updated later.
If none of that seems palatable, the way to do this kind of thing in EF5 (and is a bit more flexible) is to override SaveChanges on the context and call the proc when the type is Widget and is EntityState.Added. Or you could throw an exception instead to force devs to call the proc on their own vs using EF's DBSet Add method.
Any properties that don't need to be passed to mapped stored procedures (ever) can be marked as computed. Just add the attribute [DatabaseGenerated(DatabaseGeneratedOption.Computed)] in front of your property definitions. The proc MUST return a result set with all the "computed" values after your procedure runs, or else there will be optimistic concurrency errors. A Select * from where should be fine.
If your classes are generated, you can make a partial class to keep all these attributes safe.
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace MyEfNamespace
{
[MetadataType(typeof(MetaData))]
public partial class Widget
{
public class MetaData
{
[DatabaseGenerated(DatabaseGeneratedOption.Computed)]
public System.DateTime WidgetCreatedOn;
[DatabaseGenerated(DatabaseGeneratedOption.Computed)]
public System.DateTime WidgetLastUpdatedOn;
...
}
}
}

Attempting to use EF/Linq to Entities for dynamic querying and CRUD operations

(as advised re-posting this question here... originally posted in msdn forum)
I am striving to write a "generic" routine for some simple CRUD operations using EF/Linq to Entities. I'm working in ASP.NET (C# or VB).
I have looked at:
Getting a reference to a dynamically selected table with "GetObjectByKey" (But I don't want anything from cache. I want data from database. Seems like not what this function is intended for).
CRM Dynamic Entities (here you can pass a tablename string to query) looked like the approach I am looking for but I don't get the idea that this CRM effort is necessarily staying current (?) and/or has much assurance for the future??
I looked at various ways of drilling thru Namespaces/Objects to get to where I could pass a TableName parameter into the oft used query syntax var query = (from c in context.C_Contacts select c); (for example) where somehow I could swap out the "C_Contacts" TEntity depending on which table I want to work with. But not finding a way to do this ??
Slightly over-simplyfing, I just want to be able to pass a tablename parameter and in some cases some associated fieldnames and values (perhaps in a generic object?) to my routine and then let that routine dynamically plug into LINQ to Entity data context/model and do some standard "select all" operations for parameter table or do a delete to parameter table based on a generic record id. I'm trying to avoid calling the various different automatically generated L2E methods based on tablename etc...instead just trying to drill into the data context and ultimately the L2E query syntax for dynamically passed table/field names.
Has anyone found any successful/efficient approaches for doing this? Any ideas, links, examples?
The DbContext object has a generic Set() method. This will give you
from c in context.Set<Contact>() select c
Here's method when starting from a string:
public void Test()
{
dynamic entity = null;
Type type = Type.GetType("Contract");
entity = Activator.CreateInstance(type);
ProcessType(entity);
}
public void ProcessType<TEntity>(TEntity instance)
where TEntity : class
{
var result =
from item in this.Set<TEntity>()
select item;
//do stuff with the result
//passing back to the caller can get more complicated
//but passing it on will be fine ...
}

Entity Framework 4.1 DbContext Extending Partial Classes

Building a C# application using EF 4.1 with Database First. My question centers around using extension methods to return values through the DbContext object.
My entities were created as partial classes by the DbContext generator. I have a Projects table and a related Managers table and through the context object I can perform LINQ queries and access projects and the assigned project manager. If the Manager table has firstname and lastname fields how would I write my extension as a property or method to concatenate the first and last name fields so that when I query for a project and use the manager relation the property FullName returns the combined value?
This example has a variable _projects populated with a list of Projects created using LINQ query:
Fields["manager"].Value = _projects[i].Project.ProjectManager.FullName
I can makethe FullName property into a method and pass the id for the manager however wouldn't that make it into an additional query? Thanks for the help.
If you know that you're always going to be accessing the ProjectManager navigation property, you can include it in the initial query by using the Include method
var projects = (from p in ctx.Projects
select p)
.Include(p => p.ProjectManager)
.ToList();
Then you can add the following property to your Manager class (in a seperate file than the generated one)
public string FullName
{
get { return FirstName + " " + LastName; }
}
And access it using
var manager = projects[0].ProjectManager.FullName;
If I missinterpreted your question, could you provide an example of what your code would look like using your proposed extension method?

Access the property used in mapping entity to a table in EFv4

When we have two entities in EFv4 EDM diagram and only one table for both in the database (for instance, having table Documents and entities Invoice and Qoute), table Documents having documentTypeId column as a discriminator and set this column as a discriminator in the EDM (in Table mappings), how do we read the value of this property in our code?
We cannot assign values to it because EF does it for us under the hood (based on what we entered in Table mappings for condition) but somehow I don't get it why we are also not allowed to read it.
Imo this property is already mapped so you can't map it again. It is used to determine type of materialized entity. Why do you need such column. Usually it is enough to use is operator like:
var document = context.Documents.GetById(id);
if (document is Invoice)
{
...
}
If you only need to select subtypes you can use OfType extension method like:
var invoices = context.Documents.OfType<Invoice>().ToList();
You also don't need to set this value when adding new entity because you are adding subtype - Invoice or Quote.
Edit:
As I understand from your comment you don't need this information in query. In such case you don't need to map it. Simply use partial class of your entity and add custom property which will return your string. Sound like stupid solution but actually it would be the easiest one.
Discriminator column should be part of mapping metadata so in case of T4 template generating your entities, it could be possible to update the template so it generate such property for you.
You may want to use a single-table inheritance hierarchy, as described here.
That way, you could have an abstract Document class that includes a DocumentTypeId column. Invoices and Quotes would extend this class, but specify certain DocumentTypeId filters. However, because the original class has a DocumentTypeId column, they would each have that column as well.
Another advantage to this approach is that you could create utility methods that can act on any Document, and you could pass any Invoice or Quote to these methods.

Using Include() with inherited entities

In EF eager loading related entities is easy.
But I'm having difficulties including inherited entities when loading data using table-per-type model.
This is my model:
Entities:
ArticleBase (base article entity)
ArticleSpecial (inherited from ArticleBase)
UserBase (base user entity)
UserSpecial (inherited from UserBase)
Image
Relations are as shown on the image (omitting many columns):
In reality my users are always of type UserSpecial, since UserBase is used in another application, thus we can share credentials. That's the only reason I have two separate tables. UserBase table can't be changed in any way shape or form, because the other app would break.
Question
How am I suppose to load ArticleSpecial with both CreatedBy and EditedBy set, so that both are of type UserSpecial (that defines Image relation)?
I've tried (unsuccessfully though) these options:
1.
Using lambda expressions:
context.ArticleBases
.OfType<ArticleSpecial>()
.Include("UserCreated.Image")
.Include("UserEdited.Image");
In this case the problem is that both CreatedBy and EditedBy are related to UserBase, that doesn't define Image navigation. So I should somehow cast these two to UserSpecial type like:
context.ArticleBases
.OfType<ArticleSpecial>()
.Include("UserCreated<UserSpecial>.Image")
.Include("UserEdited<UserSpecial>.Image");
But of course using generics in Include("UserCreated<UserSpecial>.Image") don't work.
2.
I have tried using LINQ query
var results = from articleSpecial in ctx.ArticleBase.OfType<ArticleSpecial>()
join created in ctx.UserBase.OfType<UserSpecial>().Include("Image")
on articleSpecial.UserCreated.Id equals created.Id
join edited in ctx.UserBase.OfType<UserSpecial>().Include("Image")
on articleSpecial.UserEdited.Id equals edited.Id
select articleSpecial;
In this case I'm only getting ArticleSpecial object instances without related properties being set. I know I should select those somehow, but I don't know how?
Select part in my LINQ could be changed to something like
select new { articleSpecial, articleSpecial.UserCreated, articleSpecial.UserEdited };
but images are still not loaded into my context. My joins in this case are barely used to filter out articleSpecial results, but they don't load entities into context (I suppose).
This seems to be a limitation in the current version of Entity Framework (1.0) Have a look at this related SO question.
In your case including the related UserCreated and UserEdited properties in the projection is the right solution. However if you also want to populate the Image property on the UserSpecial object, you must be sure to include that as well:
var results = from articleSpecial in ctx.ArticleBase.OfType<ArticleSpecial>()
select new
{
articleSpecial,
articleSpecial.UserCreated,
((UserSpecial)articleSpecial.UserCreated).Image,
articleSpecial.UserEdited,
((UserSpecial)articleSpecial.UserEdited).Image
};
Of course this query builds on the assumption that all ArticleSpecial entities always refer to a UserSpecial entity, otherwise the casting will fail.
If this assumption isn't always true, you could express the same query using the LINQ extension methods and a multi-line lambda function to perform a safe casting:
var results = ctx.ArticleBase
.OfType<ArticleSpecial>()
.AsEnumerable()
.Select(a =>
{
var userCreated = a.UserCreated as UserSpecial;
if (userCreated != null)
{
var image = userCreated.Image;
}
var userEdited = a.UserEdited as UserSpecial;
if (userEdited != null)
{
var image = userEdited.Image;
}
return a;
});
In the latter example, you also do not need to include UserSpecial and Image entities in the results. Instead you just need to access the navigation properties on the ArticleSpecial entities during the projection phase in order to force Entity Framework to eager load the related objects.