How to change the value of a tables attribute using LINQ/LAMBDA? - entity-framework

I have an order table and an orderStatus table, their relationship is as seen below:
I want to be able to change 'StatusID' to the value 2, of a specific order (i am able to get the specific order ID, and have loaded it into an integer variable) using a lambda expression within an action result - would there be any easy way of doing this?
So far i have tried:
//get specific order ID
int currentOrderId = newConfirmedOrderLine.OrderID;
//-----
Order statusChange = new Order();
statusChange.OrderStatus.StatusID = 2;
DBAccessor.SaveChanges();
I am new to linq and lambda, so any explanation with an answer would be greatly appreciated!

If DBAccessor is a DbContext then this could/should work. You need to load the Order entity that you want to change from the DBAccessor.Order DbSet, change it by setting a property, and then call SaveChanges.
var orderStatus = DBAccessor.OrderStatus.First(x => x.StatusID == 2);
var order = DBAccessor.Order.Find(currentOrderId);
order.OrderStatus = orderStatus;
DBAccessor.SaveChanges();

Related

EF 5.0 set column equal to the default (computed) value of another column in one transaction

I have a table that has an Identity column and another column needs to have its value based on the computed identity column.
My EF code looks like this:
var context = new DBEntities();
var newTableRow = new TableRow();
newTableRow.Column1 = newTableRow.ComputedColumn;
context.TableRows.Add(newTableRow);
context.SaveChanges();
If ComputedColumn is an IDENTITY and Column1 is a nullable varchar(50) I would expect the value of Column1 to be the same as the ComputedColumn but it is null.
I have even tried this:
var context = new DBEntities();
var newTableRow = new TableRow();
context.TableRows.Add(newTableRow);
context.SaveChanges();
newTableRow.Column1 = newTableRow.ComputedColumn;
context.SaveChanges();
AND
var context = new DBEntities();
var newTableRow = new TableRow();
context.TableRows.Add(newTableRow);
context.SaveChanges();
var getTableRow = context.TableRows.Single(r => r.ComputedColumn == newTableRow.ComputedColumn);
getTableRow.Column1 = newTableRow.ComputedColumn.ToString();
context.SaveChanges();
Keep in mind that this is part of a larger transaction. What I don't want to do is complete the transaction then in a separate transaction do another update. I would like to keep everything in one transaction. This had been working in an insert proc before.
Thanks,
Brett
Your second an third example should work if ComputedColumn has DatabaseGeneratedOption.Identity. But they have separate transactions, which you don't want.
Your first example can't work. When a column has DatabaseGeneratedOption.Identity, EF reads the identity value back when executing SaveChanges. It is not aware of any special instruction you might have tried to convey with
newTableRow.Column1 = newTableRow.ComputedColumn;
As for EF, it's just an assignment with an empty value.
Maybe the best alternative is to add a computed column to your database table. You will kill two birds with one stone:
It is transactional, because the computed column just re-displays the identity column
You prevent redundancy and possible value conflicts.
I just reviewed the model and you're right there was a change I didn't notice. Column1 had been set as a computed value. Removing that value should fix the problem.

Entitykey values cannot be changed once they are set

I have a method for editing a table (Human) in my database. That table is part of a 1 to many relationship. Human is on the many side.
Human has a foreign key named idOtherTable.
Now, here is how I'm trying to change it:
Employee e = (from x in db.Human
where x.idHuman == someNumber
select x).First();
e.name = name;
e.phoneNumber = phoneNumber;
//this is how I try to change it:
e.RoleReference.EntityKey.EntityKeyValues[0].Value = editEmployee.idRole;
but it says that once is set, the value cannot be changed. How can I resolve this?

Entity Framework Foreign Key Queries

I have two tables in my entity framework, objects, and parameters which have a foreign key pointing to the object to which they belong. I want to populate a tree with all the attributes of a certain object. So in order to find those I want to do this:
String parentObject = "ParentObjectName";
var getAttributes = (from o in myDB.ATTRIBUTE
where o.PARENT_OBJECT == parentObject
select o);
However when I try to do this I get an error saying it cannot convert from type OBJECT to string, even though in the database this value is stored as a string. I have a workaround where I get an instance of the parentObject, then go through every attribute and check whether it's parent_object == parentObjectInstance, but this is much less efficient than just doing 1 query. Any help would be greatly appreciate, thanks!
Well, PARENT_OBJECT.ToString() can't be called (implicitly or explicitly) in L2E, but if it just returns a property, you can look at that directly:
String parentObject = "ParentObjectName";
var getAttributes = (from o in myDB.ATTRIBUTE
where o.PARENT_OBJECT.NAME == parentObject
select o);
...note the .NAME
Try this:
String parentObject = "ParentObjectName";
var getAttributes = (from o in myDB.ATTRIBUTE
where o.PARENT_OBJECT.ToString() == parentObject
select o);

Problem in LINQ query formation

I have written
List<int> Uids = new List<int>();
Uids = (from returnResultSet in ds.ToList()
from portfolioReturn in returnResultSet.Portfolios
from baseRecord in portfolioReturn.ChildData
select new int
{
id = baseRecord.Id
}).ToList<int>();
Getting error: 'int' does not contain a definition for 'id'
what is the problem that i created?
Thanks
Try this:
List<int> Uids = (from returnResultSet in ds.ToList()
from portfolioReturn in returnResultSet.Portfolios
from baseRecord in portfolioReturn.ChildData
select baseRecord.Id).ToList<int>();
Since you want to get a list of integers you can simply project the Id property from your query and then use the ToList extension method to buffer them into a List<T>. As a side note, are you certain that a List<T> is the right type to use here? You are forgoing the benefit of deferred execution and will not be able to stream these ids if you buffer them into a List<T>.
Your code is trying to instantiate ints, setting an id property that doesn't exist. I think the following is what you need.
Uids = (from returnResultSet in ds.ToList()
from portfolioReturn in returnResultSet.Portfolios
from baseRecord in portfolioReturn.ChildData
select baseRecord.Id).ToList<int>();
The problem is with the: select new int {} part.
Try simply doing:
List<int> Uids = new List<int>();
Uids = (from returnResultSet in ds.ToList()
from portfolioReturn in returnResultSet.Portfolios
from baseRecord in portfolioReturn.ChildData
select baseRecord.Id
)
.ToList<int>();
select new {} syntax is for defining anonymous types (where use is limited to the same function scope).
Andrew.

ADO.NET Mapping From SQLDataReader to Domain Object?

I have a very simple mapping function called "BuildEntity" that does the usual boring "left/right" coding required to dump my reader data into my domain object. (shown below) My question is this - If I don't bring back every column in this mapping as is, I get the "System.IndexOutOfRangeException" exception and wanted to know if ado.net had anything to correct this so I don't need to bring back every column with each call into SQL ...
What I'm really looking for is something like "IsValidColumn" so I can keep this 1 mapping function throughout my DataAccess class with all the left/right mappings defined - and have it work even when a sproc doesn't return every column listed ...
Using reader As SqlDataReader = cmd.ExecuteReader()
Dim product As Product
While reader.Read()
product = New Product()
product.ID = Convert.ToInt32(reader("ProductID"))
product.SupplierID = Convert.ToInt32(reader("SupplierID"))
product.CategoryID = Convert.ToInt32(reader("CategoryID"))
product.ProductName = Convert.ToString(reader("ProductName"))
product.QuantityPerUnit = Convert.ToString(reader("QuantityPerUnit"))
product.UnitPrice = Convert.ToDouble(reader("UnitPrice"))
product.UnitsInStock = Convert.ToInt32(reader("UnitsInStock"))
product.UnitsOnOrder = Convert.ToInt32(reader("UnitsOnOrder"))
product.ReorderLevel = Convert.ToInt32(reader("ReorderLevel"))
productList.Add(product)
End While
Also check out this extension method I wrote for use on data commands:
public static void Fill<T>(this IDbCommand cmd,
IList<T> list, Func<IDataReader, T> rowConverter)
{
using (var rdr = cmd.ExecuteReader())
{
while (rdr.Read())
{
list.Add(rowConverter(rdr));
}
}
}
You can use it like this:
cmd.Fill(products, r => r.GetProduct());
Where "products" is the IList<Product> you want to populate, and "GetProduct" contains the logic to create a Product instance from a data reader. It won't help with this specific problem of not having all the fields present, but if you're doing a lot of old-fashioned ADO.NET like this it can be quite handy.
Although connection.GetSchema("Tables") does return meta data about the tables in your database, it won't return everything in your sproc if you define any custom columns.
For example, if you throw in some random ad-hoc column like *SELECT ProductName,'Testing' As ProductTestName FROM dbo.Products" you won't see 'ProductTestName' as a column because it's not in the Schema of the Products table. To solve this, and ask for every column available in the returned data, leverage a method on the SqlDataReader object "GetSchemaTable()"
If I add this to the existing code sample you listed in your original question, you will notice just after the reader is declared I add a data table to capture the meta data from the reader itself. Next I loop through this meta data and add each column to another table that I use in the left-right code to check if each column exists.
Updated Source Code
Using reader As SqlDataReader = cmd.ExecuteReader()
Dim table As DataTable = reader.GetSchemaTable()
Dim colNames As New DataTable()
For Each row As DataRow In table.Rows
colNames.Columns.Add(row.ItemArray(0))
Next
Dim product As Product While reader.Read()
product = New Product()
If Not colNames.Columns("ProductID") Is Nothing Then
product.ID = Convert.ToInt32(reader("ProductID"))
End If
product.SupplierID = Convert.ToInt32(reader("SupplierID"))
product.CategoryID = Convert.ToInt32(reader("CategoryID"))
product.ProductName = Convert.ToString(reader("ProductName"))
product.QuantityPerUnit = Convert.ToString(reader("QuantityPerUnit"))
product.UnitPrice = Convert.ToDouble(reader("UnitPrice"))
product.UnitsInStock = Convert.ToInt32(reader("UnitsInStock"))
product.UnitsOnOrder = Convert.ToInt32(reader("UnitsOnOrder"))
product.ReorderLevel = Convert.ToInt32(reader("ReorderLevel"))
productList.Add(product)
End While
This is a hack to be honest, as you should return every column to hydrate your object correctly. But I thought to include this reader method as it would actually grab all the columns, even if they are not defined in your table schema.
This approach to mapping your relational data into your domain model might cause some issues when you get into a lazy loading scenario.
Why not just have each sproc return complete column set, using null, -1, or acceptable values where you don't have the data. Avoids having to catch IndexOutOfRangeException or re-writing everything in LinqToSql.
Use the GetSchemaTable() method to retrieve the metadata of the DataReader. The DataTable that is returned can be used to check if a specific column is present or not.
Why don't you use LinqToSql - everything you need is done automatically. For the sake of being general you can use any other ORM tool for .NET
If you don't want to use an ORM you can also use reflection for things like this (though in this case because ProductID is not named the same on both sides, you couldn't do it in the simplistic fashion demonstrated here):
List Provider in C#
I would call reader.GetOrdinal for each field name before starting the while loop. Unfortunately GetOrdinal throws an IndexOutOfRangeException if the field doesn't exist, so it won't be very performant.
You could probably store the results in a Dictionary<string, int> and use its ContainsKey method to determine if the field was supplied.
I ended up writing my own, but this mapper is pretty good (and simple): https://code.google.com/p/dapper-dot-net/