Friday, December 5, 2008

LINQ to SQL Entity Base Version 1.0 Final

Hi everyone,

Now that all the bugs seem to be ironed out in the the LINQ to SQL Entity Base class, it's time to release it to the world as a final version.

If you have been using RC3, there is no need to update the source code from the Final release source code as it has not changed.

As with the RC3 release, I will stress again that you need Visual Studio 2008 SP1 and .NET 3.5 SP1 to run this final release verison as it uses one of the attributes for serialization not found in the original .NET 3.5 version.

Find the final version here:


Anyway, have fun!

Cheers

Matt.


15 comments:

Anonymous said...

Hi Matt,

Congrats for the final release!

I just wonder if you have any example of the entity base being used with an asp.net application. Things like binding expressions, form views, object containers data sources and etc .... did you ever have to use it in this scenario?

Matthew Hunter said...

Hi there,

Yes, actually the whole reason for me doing this project in the first place was because of ASP.NET.

Sorry, I don't have any examples that I could provide, however there's not really any difference between using it or not when you talk about things like data binding - it pretty much works the same - except you can't use the LINQ 2 SQL Data source for Inserts,Updates, Deletes, which is pretty much tied directly to a data context without allowing tiers (Selects still work). I'd suggest using the Object Data Source.

The only other difference really is that the assembly containing the data contect needs to be available in all tiers if you've got an architecture that has tiers in seperate processes. And of course the other difference is the value add like change tracking, autosyncing with datacontext, etc..

Anonymous said...

Yep I got you. So which property should I keep say in the formView that would tell my entity has beem modified? All properties from the entity base have a private set setter so after my update has been done I get the object as not tracked....am I missing something here?

Thanks !!! Keep up with this awesome job !!!

Matthew Hunter said...

Ok, first I assume your setting "SetChangeTrackingRoot" on the parent entity before you do any mods, this is what kicks off the change tracking bit. Then between requests, you put the parent object into the session or viewstate (though you'd want it to be smallish for view state). Once you do this, you should find that you can check the EntityState property to find out if it's been modified or not.

If you are getting "not tracked", you probably aren't doing the above.

Anonymous said...

Hey Matt...I'm doing exactly what you suggested in the previous comment. I added a class that is my mid business tier and an object data source to my web page. In my business tier I set the SetChangeTrackingRoot correctly so I can see my object is in it's original state. After I do an update in my formview and go to my update method in the business tier, the object's state is "notTracked". I wonder if I have to add any other field to my datakeynames of my form view? I'm using the same sample you provided and in this case the object is a northwind customer.

Thanks again !!!

Matthew Hunter said...

Doh! I forgot to tell you that if your using the object data source, you'll need to provide an instance of the class (your state object) by use the objectcreating event on the object data source, otherwise ASP.NET will create a new object every time.

ASP.Net assumes that the object you are bound to will provide the object (i.e. assumes everything is stateless). In this instance, you need to provide it the object to bind to from the session or viewstate.


Here'e the documentation:

http://msdn.microsoft.com/en-us/library/system.web.ui.webcontrols.objectdatasource.objectcreating.aspx

From memory, I suggest doing something like

void odsCustomers_ObjectCreating(object sender, ObjectDataSourceEventArgs e)
{
e.ObjectInstance = [object];
odsCustomers.DataBind(); // May or May not be needed
}

Which will set the data binding properly to your object(s) and override the select, update, insert and delete on the object data source to do the operations. [Object] being of the type you've configured the Object Data Source to bind to.

If you need more help, i'll see if I can find some blog/forum entries on doing this.

Matthew Hunter said...

Sorry to make it clear, replace [object] with the instance of the object your retrieving from session.

Anonymous said...

Yeah Matt I've done some research and apparently that's the way to do it !

I think I'm closer than ever now but I'm still getting a quite odd exception:

Exception Details: System.Reflection.TargetException: Object does not match target type.

Source Error:

An unhandled exception was generated during the execution of the current web request. Information regarding the origin and location of the exception can be identified using the exception stack trace below.

Stack Trace:


[TargetException: Object does not match target type.]
System.Reflection.RuntimeMethodInfo.CheckConsistency(Object target) +7515851
System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture, Boolean skipVisibilityChecks) +105
System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture) +29
System.Web.UI.WebControls.ObjectDataSourceView.InvokeMethod(ObjectDataSourceMethod method, Boolean disposeInstance, Object& instance) +488
System.Web.UI.WebControls.ObjectDataSourceView.InvokeMethod(ObjectDataSourceMethod method) +39
System.Web.UI.WebControls.ObjectDataSourceView.ExecuteUpdate(IDictionary keys, IDictionary values, IDictionary oldValues) +1030
System.Web.UI.DataSourceView.Update(IDictionary keys, IDictionary values, IDictionary oldValues, DataSourceViewOperationCallback callback) +92
System.Web.UI.WebControls.FormView.HandleUpdate(String commandArg, Boolean causesValidation) +835
System.Web.UI.WebControls.FormView.HandleEvent(EventArgs e, Boolean causesValidation, String validationGroup) +509
System.Web.UI.WebControls.FormView.OnBubbleEvent(Object source, EventArgs e) +95
System.Web.UI.Control.RaiseBubbleEvent(Object source, EventArgs args) +37
System.Web.UI.WebControls.FormViewRow.OnBubbleEvent(Object source, EventArgs e) +113
System.Web.UI.Control.RaiseBubbleEvent(Object source, EventArgs args) +37
System.Web.UI.WebControls.LinkButton.OnCommand(CommandEventArgs e) +118
System.Web.UI.WebControls.LinkButton.RaisePostBackEvent(String eventArgument) +135
System.Web.UI.WebControls.LinkButton.System.Web.UI.IPostBackEventHandler.RaisePostBackEvent(String eventArgument) +10
System.Web.UI.Page.RaisePostBackEvent(IPostBackEventHandler sourceControl, String eventArgument) +13
System.Web.UI.Page.RaisePostBackEvent(NameValueCollection postData) +175
System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint) +1565

Did you come across this one???

Thanks !!!!!

Matthew Hunter said...

Hi again,

I think the issue you are having is that you ware binding to a list (perhaps from ToEntityTree()) where the types returned are not the same.

For example, if you had a car and a bus in the same list and then tried to map to it - it would fail.

However, if you made a type IAutomobile with properties/methods required and both car and bus implemented it, you could set the type you are mapping to as IAutomobile and it should work.

Does that sound like a the problem/solution that might be applicable?

Anonymous said...

Hi Matt,

Thanks again for your comments but I don't think so.

I have a form view that is bound to a Customer (northwind database).
The customer inherits from your entity base.

I'm only getting the customer by id (only one record at a time) and then trying to update the same record.

Sorry but I think I'm still missing something.....sorry to bother you again ...

Matthew Hunter said...

That's fine I don't helping - Just trying to figure out what's going on..

Sorry for the late reply, have been busy over XMAS.

Ok, it definitely doesn't like the type somewhere... Can you explain when the exception occurs, is it when your method for update is invoked? If so, double check the object types on your method and make sure that they are mapped to the correct types.

Is it possible for you to send through a sample project (just via email)? This would allow me to resolve it pretty quickly.

Anonymous said...

Hey Matt.... I just sent you an email with the code ...

Thanks dude.

Andre.

Anonymous said...

Hi Matt,

I hope you received the email I sent you a few days ago with the code sample you asked for.

Did you have a change to look into it?

BTW, my email is afgallo at gmail dot com

Thanks,
Andre.

Matthew Hunter said...

Yep,

Got the code.

Sorry - been busy. Will take a look at it soon.

Matthew Hunter said...

Hi Andre,

I had a look at the code. The reason you are getting that error is because in the objectcreating method you are setting the value to the wrong type. Instead of setting it the instance of your customer, set it to an instance of the class that contains the crud methods (your NorthwindBusiness class).

I also had a look at the code, and saw what you were doing. A straight update like that unfortunately won't work. The issue here is that the object that the ObjectDataSource passes to the Updating method is a brand new object that it has created and it has pushed the data into it - it's not the same object we started with, and it's only the public properties that are copied - all other data is lost.

To get around this issue, you'll need to transfer the values from the object provided (in the updating methods parameters) to the entity instance your want to update (i.e. the one in your session). You can do this manually, or have a look at the ShallowCopy() method in the LINQEntityBase that copies all the columns accross, you could extend the code so that it copies to an already existing object by modifying the following line to use your object instead of creating a new one:

destination = Activator.CreateInstance(entityType) as LINQEntityBase;

Also, Here's a blog on this issue, and another way around it by:

http://musingmarc.blogspot.com/search/label/ObjectDataSource

Cheers

Matt