How to create a reference to an existing record - linq

go easy on me, it's my first question :)
I've been working with linqToSql for about a month, and there is just this one thing that is bothering me...
Lets say I have an Entity Object called "Customer" and another called "CustomerType", Customer as a reference to CustomerType.
When inserting the Customer I need to set the CustumerType, I have the customerTypeID value that I want to set, so what I am doing is this:
if(c.CustomerTypeReference == null)
{
c.CustomerTypeReference = new System.Data.Objects.DataClasses.EntityReference<CustomerType>
}
c.CustomerTypeReference.EntityKey = new System.Data.EntityKey("DataContext.CustomerType", "id", value);
This works but it seems to me over complicated. Is there any other way to do this?
Please take in mind that I do not want to get the object CustomerType from the database, this example is simple but I do work with objects that contain about 100 properties.

Are you using the DBML Designer or have you hand-coded your entity classes? If you are working with the Designer, I would expect that since your table has a customerTypeID column, that there would be a property named customerTypeID in your Customer class. All you really need to do is set the value of this property to the value of the id
Customer c = new Customer();
c.customerTypeID = value;
This should work fine as long as you don't want to refer to the related entities themselves (i.e., you are just going to save this particular object, not use it right away). If you need to refer to the related entities -- say to access their properties -- it's going to have to go retrieve the values from the database. I'd have to look at the designer-generated code, but I think that the property setters on the id-value columns don't update the entity references, while the entity-reference setters do update the id-value fields.

Related

MVC Linq to SQL Update Object in database

I have a table called Code in my LINQ to SQL datacontext. I also have a class called Codes in my Models folder. What I want to do is save the updated object Codes to my database table Code. Is this possible?
In my controller, I would pass the edited Object to my Model. My CodesRepository file contains this:
public Codes EditCode(Codes CodeToEdit)
{
private EventsDataContext _db = new EventsDataContext();
Codes C = new Codes();
C = CodeToEdit;
_db.Codes.InsertOnSubmit(C); //error here, something about invalid arguments
//InsertOnSubmit is for adding a new object, but I don't know the syntax
// for editing an existing object.
_db.SubmitChanges();
}
This is probably not the correct way of doing this so can someone point me in the right direction? Do I even need a class called Codes or do I need to somehow just use my database table? Thanks.
Solution: I decided to change from Linq to SQL to an Entity Framework and it works much better. This way, I don't have to define my Codes class since it comes straight from the database and I was able to delete the Codes class file.
You should use DataContext.Attach when you get an object back that corresponds to en existing row in the database. For Linq-to-sql's optimistic concurrency handling to work this requires that you either have the original, unsaved object available, or that you have a TimeStamp column in the database. The latter is preferred, as it only requires one extra field to be handled (probably through a hidden field in the web form).

Can I use the auto-generated Linq-to-SQL entity classes in 'disconnected' mode?

Suppose I have an automatically-generated Employee class based on the Employees table in my database.
Now suppose that I want to pass employee data to a ShowAges method that will print out name & age for a list of employees. I'll retrieve the data for a given set of employees via a linq query, which will return me a set of Employee instances. I can then pass the Employee instances to the ShowAges method, which can access the Name & Age fields to get the data it needs.
However, because my Employees table has relationships with various other tables in my database, my Employee class also has a Department field, a Manager field, etc. that provide access to related records in those other tables. If the ShowAges method were to invoke any of those methods, this would cause lots more data to be fetched from the database, on-demand.
I want to be sure that the ShowAges method only uses the data I have already fetched for it, but I really don't want to have to go to the trouble of defining a new class which replicates the Employee class but has fewer methods. (In my real-world scenario, the class would have to be considerably more complex than the Employee class described here; it would have several 'joined' classes that do need to be populated, and others that don't).
Is there a way to 'switch off' or 'disconnect' the Employees instances so that an attempt to access any property or related object that's not already populated will raise an exception?
If not, then I assume that since this must be a common requirement, there might be an already-established pattern for doing this sort of thing?
maybe not the answer you're looking for,but how about projecting the results of your query into a more light-weight POCO, eg:
var employeePOCOs = from e in l2sEmployees
select new EmployeePOCO
{
Id = e.Id,
Name = e.FirstName + " " + e.LastName
};
where EmployeePOCO is a predefined class
would that help? I've used this when returning Entity Framework objects back through an AJAX call where the output was going to JSON, and it seemed to do the trick.
One way to do this is to 'detach' the entity from its database context. Take a look at an answer I gave to a similar question. It shows you a couple ways of detaching entities.

Using LINQ with stored procedure that returns multiple instances of the same entity per row

Our development policy dictates that all database accesses are made via stored procedures, and this is creating an issue when using LINQ.
The scenario discussed below has been somewhat simplified, in order to make the explanation easier.
Consider a database that has 2 tables.
Orders (OrderID (PK), InvoiceAddressID (FK), DeliveryAddressID (FK) )
Addresses (AddresID (PK), Street, ZipCode)
The resultset returned by the stored procedure has to rename the address related columns, so that the invoice and delivery addresses are distinct from each other.
OrderID InvAddrID DelAddrID InvStreet DelStreet InvZipCode DelZipCode
1 27 46 Main St Back St abc123 xyz789
This, however, means that LINQ has no idea what to do with these columns in the resultset, as they no longer match the property names in the Address entity.
The frustrating thing about this is that there seems to be no way to define which resultset columns map to which Entity properties, even though it is possible (to a certain extent) to map entity properties to stored procedure parameters for the insert/update operations.
Has anybody else had the same issue?
I'd imagine that this would be a relatively common scenarios, from a schema point of view, but the stored procedure seems to be the key factor here.
Have you considered creating a view like the below for the stored procedure to select from? It would add complexity, but allow LINQ to see the Entity the way you wanted.
Create view OrderAddress as
Select o.OrderID
,i.AddressID as InvID
,d.AddressID as DelID
...
from Orders o
left join Addresses i
on o.InvAddressID= i.AddressID
left join Addresses d
on o.DelAddressID = i.AddressID
LINQ is a bit fussy about querying data; it wants the schema to match. I suspect you're going to have to bring that back into an automatically generated type, and do the mapping to you entity type afterwards in LINQ to objects (i.e. after AsEnumerable() or similar) - as it doesn't like you creating instances of the mapped entities manually inside a query.
Actually, I would recommend challenging the requirement in one respect: rather than SPs, consider using UDFs to query data; they work similarly in terms of being owned by the database, but they are composable at the server (paging, sorting, joinable, etc).
(this bit a bit random - take with a pinch of salt)
UDFs can be associated with entity types if the schema matches, so another option (I haven't tried it) would be to have a GetAddress(id) udf, and a "main" udf, and join them:
var qry = from row in ctx.MainUdf(id)
select new {
Order = ctx.GetOrder(row.OrderId),
InvoiceAddress = ctx.GetAddress(row.InvoiceAddressId),
DeliveryAddress = ctx.GetAddress(row.DeliveryAddressId)) };
(where the udf just returns the ids - actually, you might have the join to the other udfs, making it even worse).
or something - might be too messy for serious consideration, though.
If you know exactly what columns your result set will include, you should be able to create a new entity type that has properties for each column in the result set. Rather than trying to pack the data into an Order, for example, you can pack it into an OrderWithAddresses, which has exactly the structure your stored procedure would expect. If you're using LINQ to Entities, you should even be able to indicate in your .edmx file that an OrderWithAddresses is an Order with two additional properties. In LINQ to SQL you will have to specify all of the columns as if it were an entirely unrelated data type.
If your columns get generated dynamically by the stored procedure, you will need to try a different approach: Create a new stored procedure that only pulls data from the Orders table, and one that only pulls data from the addresses table. Set up your LINQ mapping to use these stored procedures instead. (Of course, the only reason you're using stored procs is to comply with your company policy). Then, use LINQ to join these data. It should be only slightly less efficient, but it will more appropriately reflect the actual structure of your data, which I think is better programming practice.
I think I understand what you're after, but I could wildy off...
If you mock up classes in a DBML (right-click -> new -> class) that are the same structure as your source tables, you could simply create new objects based on what is read from the stored procedure. Using LINQ to objects, you could still query your selection. It's more code, but it's not that hard to do. For example, mock up your DBML like this:
Pay attention to the associations http://geeksharp.com/screens/orders-dbml.png
Make sure you pay attention to the associations I added. You can expand "Parent Property" and change the name of those associations to "InvoiceAddress" and "DeliveryAddress." I also changed the child property names to "InvoiceOrders" and "DeliveryOrders" respectively. Notice the stored procedure up top called "usp_GetOrders." Now, with a bit of code, you can map the columns manually. I know it's not ideal, especially if the stored proc doesn't expose every member of each table, but it can get you close:
public List<Order> GetOrders()
{
// our DBML classes
List<Order> dbOrders = new List<Order>();
using (OrderSystemDataContext db = new OrderSystemDataContext())
{
// call stored proc
var spOrders = db.usp_GetOrders();
foreach (var spOrder in spOrders)
{
Order ord = new Order();
Address invAddr = new Address();
Address delAddr = new Address();
// set all the properties
ord.OrderID = spOrder.OrderID;
// add the invoice address
invAddr.AddressID = spOrder.InvAddrID;
invAddr.Street = spOrder.InvStreet;
invAddr.ZipCode = spOrder.InvZipCode;
ord.InvoiceAddress = invAddr;
// add the delivery address
delAddr.AddressID = spOrder.DelAddrID;
delAddr.Street = spOrder.DelStreet;
delAddr.ZipCode = spOrder.DelZipCode;
ord.DeliveryAddress = delAddr;
// add to the collection
dbOrders.Add(ord);
}
}
// at this point I have a List of orders I can query...
return dbOrders;
}
Again, I realize this seems cumbersome, but I think the end result is worth a few extra lines of code.
this it isn't very efficient at all, but if all else fails, you could try making two procedure calls from the application one to get the invoice address and then another one to get the delivery address.

Linq to Entities, EntityReferences and DataGridViews

I am trying to select certain fields from my entity to be used as the datasource for a datagridview, but I haven't been able to make it work. Is such a thing possible? For example, I have a Customers entity that contains several entityreferences. I want to take fields from the customers entity and from within those entityreferences and display them in the datagridview. I haven't been able to come up with a Linq query to accomplish this, and even when you simply use the entire entity as the datasource the fields within the entityreferences are not displayed. Any idea what I am doing wrong? Thanks for the help.
from customer in context.customers
select new
{
Name = customer.Name,
City = customer.Address.City
}
that will create a custom object and you can see the second property is referencing an entity field on the primary entity.. basically just transform the data to a new object and bind the enumerable generated to the grid.
sorry if this is a little mumbled, typing on my phone.
Caveat: This is not tested with entity framework references.
When using object data sources you can reference properties of object references, but you must first cast the object:
<asp:Label ID="lblCity" runat="server" Text='<%# ((Customer)Container.DataItem).Address.City%>'></asp:Label>
Could this be your problem accessing properties of the entity references?

Linq To SQL Without Explicit Foreign Key Relationships

I am working with a few legacy tables that have relationships, but those relationships haven't been explicitly set as primary/foreign keys. I created a .dbml file using "Linq To Sql Classes" and established the proper Case.CaseID = CaseInfo.CaseID association. My resulting class is CasesDataContext.
My Tables (One to many):
Case
------------------
CaseID (int not null)
MetaColumn1 (varchar)
MetaColumn2 (varchar)
MetaColumn3 (varchar)
...
CaseInfo
------------------
CaseInfoID (int)
CaseID (int nulls allowed)
CaseInfoMeta (varchar)
...
I'm new to LinqToSQL and am having trouble doing..
CasesDataContext db = new CasesDataContext();
var Cases = from c in db.Cases
where c.CaseInfo.CaseInfoMeta == "some value"
select c;
(Edit) My problem being that CaseInfo or CaseInfos
is not available as a member of Cases.
I heard from a colleague that I might try ADO.Net Entity Data Model to create my Data Context class, but haven't tried that yet and wanted to see if I'd be wasting my time or should I go another route. Any tips, links, help would be most appreciated.
Go back to the designer and check the relation is set up correctly. Here is one real life example, with BillStateMasters have "CustomerMasters1" property (customers for the state):
Ps. naming is being cleaned up ...
Update 1: You also need to make sure both tables have a primary defined. If the primary key isn't defined on the database (and can't be defined for whatever reason), make sure to define them in the designer. Open the column's properties, and set it as primary key. That said, entity tracking also won't work if you haven't a primary key for the entity, which for deletes means it silently doesn't updates the entity. So, make sure to review all entities and to have them all with a primary key (as I said, if it can't be on the db, then on the designer).
CasesDataContext db = new CasesDataContext();
var Cases = from c in db.Cases
join ci in db.CaseInfo on
ci.ID equals c.InfoID
where ci.CaseInfoMeta == "some value"
select new {CASE=c, INFO=ci};
my "join" linq is a bit rusty, but the above should get close to what you're after.
Is the association set to One to One or One to Many? If you have the association set to One to Many, then what you have is an EntitySet, not an EntityRef and you'll need to use a where clause on the dependent set to get the correct value. I suspect that you want a One to One relationship, which is not the default. Try changing it to One to One and see if you can construct the query.
Note: I'm just guessing because you haven't actually told us what the "trouble" actually is.
Your query looks correct and should return a query result set of Case objects.
So... what's the problem?
(Edit) My problem being that CaseInfo
is not available under Cases... i.e.
c.CaseInfo doesn't exist where I'm
assuming it would be if there were
explicit primary/foreign key
relationships.
What do you mean by "not available"? If you created the association in the designer as you say you did, then the query should generate SQL something along the lines of
SELECT [columns]
FROM Case INNER JOIN CaseInfo
ON Case.CaseID = CaseInfo.CaseID
WHERE CaseInfo.CaseInfoMeta = 'some value'
Have you debugged your linq query to get the SQL generated yet? What does it return?
Couple of things you might want to try:
Check the properties of the association. Make sure that the Parent property was created as Public. It does this by default, but something may have changed.
Since you're not getting CaseInfo on C, try typing it the other direction to see if you get ci.Case with intellisense.
Delete and recreate the association all together.
There's something very basic going wrong if the child members are not showing up. It might be best to delete the dbml and recreate the whole thing.
If all else fails, switch to NHibernate. :)
After a few tests, I'm pretty sure the FK relationships are required in the DB regardless of whatever associations are created in Linq-to-SQL. i.e. if you don't have them explicitly set in the DB, then you will have to do a join manually.
Is this c#? I think you need == instead of = on this line:
where c.CaseInfo.CaseInfoMeta = "some value"
should read
where c.CaseInfo.CaseInfoMeta == "some value"

Resources