How to add field not mapped to table in Linq to Sql - c#

In Entity Framework I can apply NotMapped attribute to a property which I do NOT want to create a column in a database table for. How to get the same effect for auto generated classes in DBML file?
I have a StoredProcedure that returns some additional fields.
I called SP like:
[global::System.Data.Linq.Mapping.FunctionAttribute(Name = "dbo.sp_GetSupplierArticles")]
public ISingleResult<SupplierArticle> GetSupplierArticles([global::System.Data.Linq.Mapping.ParameterAttribute(DbType = "BigInt")] long mainArticleId, [global::System.Data.Linq.Mapping.ParameterAttribute(DbType = "BigInt")] long? userId)
{
IExecuteResult result = this.ExecuteMethodCall(this, ((MethodInfo)(MethodInfo.GetCurrentMethod())), mainArticleId, userId);
return ((ISingleResult<SupplierArticle>)(result.ReturnValue));
}
Necessary field I added into the separated partial class. Without any additional attributes it returns default value for my and applied [Column(IsDbGenerated = false)] in the separated partial class:
public partial class SupplierArticle
{
[Column(IsDbGenerated = false)]
public double Extra { get; set; }
}
So it works until I try to get SupplierArticle using another query (not my stored procedure):
db.LoadOptions = db.GenerateDataLoadOptions(entitiesToInclude);
var query =
from shoppingCartItem in db.ShoppingCartItems
where shoppingCartItem.UserId == userId
select shoppingCartItem;
return query.ToList();
My entity is loaded due to LoadOptions (passed in entitiesToInclude parameter).
In this query and another which try to load "poor" entity with properties that defined in .dbml file I get exception:
Invalid column name 'Extra' and the same message for each additional property.
What is the proper way to extend entity or how to avoid that exception?
UPD:
If I remove all attributes exception no longer occurs. But added properties are not initialized when SP returns a result.

I would suggest creating a complex type for that stored procedure. I would even go as far as creating complex types for all of your stored procedures as this is best practice. You can then add an extension method, or a method to your partial classes that will convert the complex type returned from the stored procedure to it's related entity, and vice versa. Another option would be to include a foreign key to your complex stored procedure type, and a navigation property pointing to the correct entity.
These are, of course, solutions to a problem that EF itself doesn't address. This is expected as EF is an ORM and is not concerned with what's not persisted.

A SQL View could be used if you wanted to. The View is composible and LINQ to SQL does not distinguish it from a Table. First rename the original table. Then make a View with the same name as the original table, while including the extra column with a default value. Let the Stored Procedure use the table with the new name. Of course any other SQL objects with references to the table need to be updated with the new table name. Now both LINQ to SQL and the SP will be happy.

Related

how to tell Entity Framework to ignore database generates values for insert or update?

I'm new to Entity Framework in C#.
I'm having one computational column in my table table1(example). I will calculate the computational column value based on the other columns value. I don't want Entity Framework to include the computational column while performing insert/update operations. How can I make the EF to avoid that particular column. But I want to set the value for that particular column manually.
I searched for the same but i couldn't able to get the answer for my question. Kindly help me and thanks in advance.
You can use the NotMapped Annotation
Code first convention dictates that every property that is of a
supported data type is represented in the database. That property can
be created dynamically and does not need to be stored. You can mark
any properties that do not map to the database with the NotMapped
annotation.
[NotMapped]
public string Something
{
get
{
return _something;
}
set
{
_something = value
}
}
Update : this is will not map to the dB, so is probably not what you are looking for
Just to make this a more complete the DatabaseGenerated Annotation, are the droids you are looking for
An important database features is the ability to have computed
properties. If you're mapping your Code First classes to tables that
contain computed columns, you don't want Entity Framework to try to
update those columns. But you do want EF to return those values from
the database after you've inserted or updated data. You can use the
DatabaseGenerated annotation to flag those properties in your class
along with the Computed enum. Other enums are None and Identity.
Which can be used with the DatabaseGeneratedOption
Computed : The database generates a value when a row is inserted or updated.
Identity : The database generates a value when a row is inserted.
None : The database does not generate values.
[DatabaseGenerated(DatabaseGenerationOption.Computed)]
public string Something { get; set; }
As you calculate your column server side the correct way is to configure the field at the context level with:
HasComputedColumnSql for ef-core
DatabaseGeneratedAttibute for EF-6 (HasDatabaseGeneratedOption for the fluent api)
If you use NotMapped, you will not get the value from the database.

How to map user defined table valued function to EF 6 database first entity collection?

I am trying to solve a problem with mapping original entity on UDF execution.
I have this scenario:
CREATE FUNCTION [dbo].[GetUsers]
(
#password nvarchar(50) NULL
)
RETURNS TABLE
AS
RETURN
(
SELECT UserID, Username FROM User
)
Assume table users has only those two columns(int and nvarchar).For obvious reasons I skipped any logic from this procedure. It simply returns all rows and columns from table User now.
I have mapped table User as entity User and is accessible from dbcontext. And now I want it to be returned from this procedure as IQueryable. I specifically dont want to use result set of "Complex" type but the original entity User.
When I do the function import and set "Returns collection of" to entities - User , it is not working, throws an exception.
Code it generates in dbcontext class looks like this:
[DbFunction("Entities", "GetUsers")]
public virtual IQueryable<User> GetUsers(string password)
{
var passwordParameter = password != null ?
new ObjectParameter("password", password) :
new ObjectParameter("password", typeof(string));
return ((IObjectContextAdapter)this).ObjectContext.CreateQuery<User>("[Entities].[GetUsers](#password)", passwordParameter);
}
so when I call the function using:
var result = dbcontext.GetUsers("pass");
it throws and exception: 'Entities.GetUsers' cannot be resolved into a valid type or function. Near member access expression, line 1, column 11.
"Entities" is indeed correct name of my dbcontext class.
Do I have my function wrong or what can be done about it to make this scenario work?
Thanks a lot
The only problem consisted in bug of entity framework where it cant obviously work with different name/type of connection strings than "Entities" (its the default one what ADO.NET model creates). I modified the T4 template a long time ago. Till moment i wanted to call UDF i never had any problem. It was using different name and kind of connection string which I am sharing across multiple libraries and not all of them support that weird type of connection string looking like:
connectionString="metadata=res:///DataModel.csdl|res:///DataModel.ssdl|res://*/..."
one.
public partial class Entities : DbContext
{
public Entities() : base("name=Entities")
{
}
...
}
When I put it back like above, it started working.

How does Find() Linq Work? how does base the find(id)?

Basically I know that find() works when it checks the entity by the stated primary id. My question is I have a Model and one of its property have [Key] data annotation but this column is not the actual primary key in the database.
Something like this
public class ModelMetadata (I'm using a metadata)
{
public int ID{get;set;} <<--actual rownum or db id
[Key]
public guid ItemId{get;set;} <<-- my desired id for find()
public string prop1{get;set;}
}
now if I use dbcontext.Model.Find(id) will it return the result based on the 'ItemId'? or the actual assign Primary key 'ID'?
Thank you.
Use a where conditional single or default like
User myUser = myDBContext.Users.SingleOrDefault(user => user.Username == username);
From Programming Entity Framework: DbContext:
One of the great things about Find is that it doesn't unnecessarily
query the database. It's also capable of finding newly added objects
that haven't yet been saved to the database. Find uses a simple set of
rules to locate the object (in order of precedence):
Look in memory for an existing entity that has been loaded from the database or attached to the context.
Look at added objects that have not yet been saved to the database.
Look in the database for entities that have not yet been loaded into memory.

Entity Framework: Adding a scalar property which is equal to a FK id

Short Question:
Basically I am trying to add a scalar property to my entity which holds the ID of a FK entity.
What I have tried to do thus far:
What I have tried so far is adding the scalar property (called ChildId) and mapped it to the matching column in the database. Now as you can imagine I get some exceptions when I try and do this because entity framework complains that the FK id is being managed in two places, once through x.ChildId and the other through x.Child.ChildId.
Now I get why it is doing this but I need some why to be able to have a scalar property which is automatically populated with the ChildId.
What I know I could do but really don't want to:
I realize that I could write a linq query that does something like the following (where I have implemented the other half of the partial class and added a property there called ChildId):
from x in db.Parent
select new Parent { ParentName = x.ParentName, ..., ChildId = x.Child.ChildId }
But this is extremely messy, particular when I have 30 odd queries that return a parent object, this mapping would need to be repeated for each query...
Also I realize that after I have executed the query I could go something like:
var childId = parent.Child.Id;
But this would cause either an extra query to be triggered, or if I was proactively loading child, and in either case I would be pulling out a lot more data than I need when I only want the ID...
The required end result:
So how do I get around some of these limitations so that I can write my queries like so (or something very similar):
from x in db.Parent
select x
And have it so that I can either go:
var childId = parent.Child.Id; //Where in this case the only property retrieved would be the Id
//Or
var childId = parent.ChildId;
Cheers
Anthony
EDIT:
Hey thanks for the reply...
I just figured this out for myself as well. Basically I was thinking that if EF supports lazy loading it must be storing the ID somewhere. Then it clicked that it must be in the reference... Hence for me it worked out being something like:
destination.PlanTypeId = (int)source.PlanTypeReference.EntityKey.EntityKeyValues[0].Value;
Also thanks for the idea of creating the extension property... will be very useful.
Did you try using parent.ChildReference.EntityKey? It doesn't need to be additionaly loaded and is holding FK. You can write extension method to get key easier.

How to use a stored procedure in ADO.NET Entity Framework

I have 3 tables; I write a stored procedure in ADO.NET Entity Framework.
ALTER PROCEDURE [dbo].[sp_GetDepartmanData]
(#departman nvarchar(50))
BEGIN
SELECT
d.ID, d.Name as DepartmanName,
sb.Salary, sb.email,
sp.Name, sp.SurName, sp.Phone, sp.Married, sp.Address
FROM
Departman d
INNER JOIN StaffsBusiness sb ON d.ID = sb.StaffsPersonelDepartmanID
INNER JOIN StaffsPersonel sp ON sb.StaffsPersonelID = sp.ID
WHERE
d.Name = #departman
END
I need a stored procedure function I write below:
var staffPersonel = staffContext.GetPersonelInformationWithDepartmanID("Yazılım");
gvPersonel.DataSource = staffPersonel;
gvPersonel.DataBind();
GetPersonelInformationWithDepartmanID function I write from SQL (user defined function in ADO.NET Entity Framework) there are 3 alternative (it is silly!!!) but i have 3 joininig table!!!. How can i use if i join 3 table before?
Okay, you need a few steps here:
add your stored procedure sp_GetDepartmanData to your Entity Framework model
(as an aside - it's is strongly recommend NOT to call your stored procedures sp_(something) - use of the sp_ prefix is reserved for Microsoft-only system stored procedures)
since your stored procedure is returning a set of data, you will need to create a conceptual entity for it first, before you can use your stored proc; in the Entity Designer, create a new entity and call it some useful name like DepartmentDataEntityType or something; add all the fields being returned from the stored procedure to that entity type
now, you can create your function import in the entity data model - go to the model browser, in the "model.store" section go to your stored procedure, and right-click on "create function import"
you can now give your function in the object context a name and define what it returns - in this case, pick your newly created entity type (e.g. DepartmentDataEntityType from above)
you're done!
You should now have a function import something like:
public global::System.Data.Objects.ObjectResult<DepartmentDataEntityType> GetPersonelInformationWithDepartmanID(global::System.String departmentName)
{
global::System.Data.Objects.ObjectParameter departmentNameParameter;
departmentNameParameter = new global::System.Data.Objects.ObjectParameter("departmentNameParameter", departmentName);
return base.ExecuteFunction<DepartmentDataEntityType>("sp_GetDepartmanData", departmentNameParameter);
}
This function on your object context can now be call to retrieve the data via the stored procedure from your database.
Marc
Edit:
If you are getting a mapping error ("Error 3027: No mapping specified for the following EntitySet/AssociationSet") after doing this, it's because the entity you created is not mapped to anything and is only ever used when the function import populates a collection of these entities. You either need to map this entity to a data store somehow or you need to change it to a complex type.
To create a complex type simply open up the EF designer and right-click on an empty area. Go to Add > Complex Type. You should see a new complex type appear in the model browser. Right click it and add scalar properties similar to how you added properties to your entity. Then delete your entity and rename your complex type the same as the entity.
That's all you have to do :)
How do you create this "conceptual entity"?
If I create an entity which is not mapped to the I get the following error: "Entity type 'foobar' is not mapped to the database.
here http://social.msdn.microsoft.com/Forums/en-US/adodotnetentityframework/thread/cd71317f-407f-4038-9a30-17dd7f529aa3
and here http://www.danrigsby.com/blog/index.php/2009/05/20/entity-framework-40-scalar-and-void-functions/

Categories