MVC Linq to SQL Update Object in database - model-view-controller

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).

Related

Entity Framework returns different result with AsNoTracking

I use Entity Framework in combination with an Oracle database. If I create a query like
myLinqStatement.ToListAsync()
I get wrong data returned as a result. If I change the statement to
myLinqStatement.AsNoTracking.ToListAsync()
I get the correct data.
I also checked the native SQL query, which is generated by myLinqStatement.ToListAsync(). The generated SQL query is correct, because I get the correct data.
So is there a problem in the mapping? And why is it working with AsNoTracking?
Thanks!
What AsNoTracking does is to retrieve the data without attaching it to the context, hence any changes you apply over the data do not take effect unless you attach it again so that EF knows it should track its changes.
The code snippets you've provided do not show the whole picture, from the moment a context is created, but is it possible that other parts of your code mutate data before you call myLinqStatement.ToListAsync()?
As you mention that myLinqStatement.AsNoTracking.ToListAsync() returns expected data, makes me assume that there are some side effects in your code that AsNoTracking simply is not aware so just returns whatever it finds in your db
I came across this question because I had a similar issue with Entity Framework Core querying a DB view, the issue was cause because view didn't have a key defined, after defining a key for the entity that map to that DB view, the query returned the same result in both cases (using AsNoTracking or without using it).
In T-SQL a key for a DB view can be defined this way:
CREATE UNIQUE CLUSTERED INDEX UQ_MyDBViewName_ColumnKey
ON dbo.MyDBViewName (ColumnKey);
And in code, you can map the key using the [Key] attribute in the corresponding property of the entity or using the EF fluent API. It will depend of what the project is using.
Either way, using AsNoTracking on a query that goes directly to a DB view makes a lot of sense. Also, if for some reason the query of the view does not allow us to define a key for that view, then the option is to use AsNoTracking.
Hope it helps anyone else having the same issue.

linq to sql, how to define DataContext without specifying Table properties

My intent is to create a generic (not in C# meaning) database model for Windows Phone using linq to sql. User of such model should be able to pass an array of his data object types (classes marked with Table attribute) to model's contstructor, and then model should take care about adding related tables to database and provide API for CRUD operations.
But then I've found out that in order to add tables to database, your data context (class inherited from DataContext class) have to declare each table as a property! That's embarrassing. Does this fact mean that my idea is not implementable? Because I obviously cannot add properties to my DataContext-based in the runtime.
So my question is, am I right in my judgments? If yes, are there some workarounds to solve this issue?
Thanks in advance.
EDIT: better question tagging, for somebody finally notice this.
You do not need to use a strongly typed DataContext (a class inheriting from DataContext and declaring properties for each table). You can do something like the following instead
var context = new DataContext("connection string", new AttributeMappingSource());
var table = context.GetTable<T>();
where T is some type marked with the Table attribute.

Using Linq SubmitChanges without TimeStamp and StoredProcedures the same time

I am using Sql tables without rowversion or timestamp. However, I need to use Linq to update certain values in the table. Since Linq cannot know which values to update, I am using a second DataContext to retrieve the current object from database and use both the database and the actual object as Input for the Attach method like so:
Public Sub SaveCustomer(ByVal cust As Customer)
Using dc As New AppDataContext()
If (cust.Id > 0) Then
Dim tempCust As Customer = Nothing
Using dc2 As New AppDataContext()
tempCust = dc2.Customers.Single(Function(c) c.Id = cust.Id)
End Using
dc.Customers.Attach(cust, tempCust)
Else
dc.Customers.InsertOnSubmit(cust)
End If
dc.SubmitChanges()
End Using
End Sub
While this does work, I have a problem though: I am also using StoredProcedures to update some fields of Customer at certain times. Now imagine the following workflow:
Get customer from database
Set a customer field to a new value
Use a stored procedure to update another customer field
Call SaveCustomer
What happens now, is, that the SaveCustomer method retrieves the current object from the database which does not contain the value set in code, but DOES contain the value set by the stored procedure. When attaching this with the actual object and then submit, it will update the value set in code also in the database and ... tadaaaa... set the other one to NULL, since the actual object does not contain the changed made by the stored procedure.
Was that understandable?
Is there any best practice to solve this problem?
If you make changes behind the back of the ORM, and don't use concurrency checking - then you are going to have problems. You don't show what you did in step "3", but IMO you should update the object model to reflect these changes, perhaps using OUTPUT TSQL paramaters. Or; stick to object-oriented.
Of course, doing anything without concurrency checking is a good way to lose data - so my preferred option is simply "add a rowversion". Otherwise, you could perhaps read the updated object out and merge things... somehow guessing what the right data is...
If you're going to disconnect your object from one context and use another one for the update, you need to either retain the original object, use a row version, or implement some sort of hashing routine in your database and retain the hash as part of your object. Of these, I highly recommend the Rowversion option as well. Using the current value as the original value like you are trying to do is only asking for concurrency problems.

Creating custom class for every Stored Procedure using linq to SQL?

I'm using stored procedure in LINQ, i know it will generate a class T(procedure name + "Result") for me automatically to store the data.
If the name of stored procedure is spCampus, the generated class will be spCampusResult.
My Question:
when i'm using SP should i create custom class that replicate all the properties ( i'm refering to whatever the .dbml creates when you drag and drop the SP)
in my situation i will be using SP... is that fair to say i will be treating as a class object and pass around from model to controller and to view ?
or i will be better off creating a new custom business object contining all the props from .dbml ?
i havent get any clear cut answer
anybody?
In the designer you can shape the object any way you see fit. You can change the names of the properties you can change the name of the object returned from the sproc if you want to. It is also my understanding that you can change the protection levels on the properties as well. This to me means that you can use the LINQ2SQL generated objects as your DTO's or you business objects because you have the power to shape them as you see fit in the designer and since they are partial classes you can extend their behavior without touching the generated class. Hope this helps.

How to create a reference to an existing record

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.

Resources