LubosSykora

hi,

i'm playing with linq to sql a bit and have a question :-)

i have something like following and i just wonder how come the updating works what is the mechanism between DataConext.Customer (represent the table) and Customer object which keeps track of changes - i mean i haven't implemented neither INotifyPropertyChanged on object nor INotifyCollectionChanged...

kindly thanks anybody for answering this maybe stupid question...

L

CustomerCollection customers = DataProvider.GetCustomerCollection();

customers[3].FirstName = customers[3].FirstName + "XXX";

DataProvider.UpdateCustomerCollection(customers);

+

public static CustomerCollection GetCustomerCollection()

{

var query = DataContext.Customer.Select(c => c);

CustomerCollection retVal = new CustomerCollection();

foreach (var item in query)

{

retVal.Add(item);

}

return retVal;

}

public static void UpdateCustomerCollection(CustomerCollection customers)

{

DataContext.SubmitChanges();

}



Re: LINQ Project General dlinq - update

Joe Albahari

Hi Lubos

No - it's not a silly question!

If your types don't implement the INotifyPropertyXXX interfaces, then LINQ to SQL makes a copy of each entity's original state - as it first populates them. Then, when you call SubmitChanges, it compares its copy against the current state of each tracked object (on a field-by-field or property-by-property basis) to determine which entities have changed. This creates some overhead (both in memory and time) which is why the INotifyPropertyXXX interfaces are normally used.

Regards

Joe





Re: LINQ Project General dlinq - update

LubosSykora

hi,

thanks a lot for your answer.

I got additional question - is it somehow possible to map CustomerCollection to DataContext.Customer property so that it'd keep track of deleted customers (removing from collection) or is there any better way how to handle that than overriding of Remove (CustomerCollection derieve from ObservableCollection<Customer>) and keeping it all removed items in other list (and then od updating this collection remove those items from DataContext.Customer)

regards

L





Re: LINQ Project General dlinq - update

Keith Farmer

I'm uncertain what you are attempting to achieve. Are you trying to determine what the inserted, removed, and modified entities are

If so, then dataContext.GetChangeSet() can provide you that information.

However, it should be noted that getting the set of changes all the time is not a particularly good use of resources.






Re: LINQ Project General dlinq - update

LubosSykora

hi,

what i want is following...

I have method returning CustomerCollection. Then i work with this collection further (adding new items, removing, modifying existing). Then i have UpdateCustomerCollection() method which must handle all changes done on this collection. In last snippet is how i handle removing items from collection which then shall be considered during update (CustomerCollection derieves BaseCollection<Customer>).

My question was if it's anyhow possible to bind DataContext.Customer (bound to Customer table in db) to CustomerCollection or if there's any better way to handle adding and removing items...

regards

L

public static CustomerCollection GetCustomerCollection()

{

var query = DataContext.Customer.Select(c => c).OrderBy(c => c.LastName);

CustomerCollection retVal = new CustomerCollection();

foreach (var item in query)

{

retVal.Add(item);

}

return retVal;

}

public static void UpdateCustomerCollection(CustomerCollection customers)

{

foreach (var item in customers.Removed)

{

if (DataContext.Customer.Contains(item))

DataContext.Customer.Remove(item);

}

foreach (var item in customers)

{

if (!DataContext.Customer.Contains(item))

DataContext.Customer.Add(item);

}

DataContext.SubmitChanges();

}

public class BaseCollection<T> : ObservableCollection<T>

{

...

#region Properties

public List<T> Removed

{

get { return removed; }

}

#endregion

#region Overrides

protected override void RemoveItem(int index)

{

removed.Add(this[index]);

base.RemoveItem(index);

}

#endregion





Re: LINQ Project General dlinq - update

Keith Farmer

Here's one approach: encapsulate the data context, and use it to do the change tracking for you. That's why it's there. Another variation would be to pass it a Func that would take a TDataContext and return an IQueryable<T>, which is then converted with ToList() and stored internally. Then the Add/Remove work on *both* the context and the list. (The list to provide a view of what's in the context, and the context to handle change tracking).

Try this out, tell me if it works.

Code Block

public static class EntityCollectionFactory

{

// usage: var collection =

// EntityCollectionFactory.Create(

// (Northwind db) => db.Customers.Where(c => c.City == "London")

// );

public static IEntityCollection<T> Create<T, TDataContext>(

Func<TDataContext, IQueryable<T>> query

)

where TDataContext: DataContext

{

return new EntityCollection<T, TDataContext>(query);

}

}

public interface IEntityCollection<T>: ICollection<T>, IDisposable

{

void SubmitChanges();

}

public class EntityCollection<T, TDataContext>: IEntityCollection<T>

where TDataContext: DataContext

{

TDataContext db;

Func<TDataContext, IQueryable<T>> query;

List<T> list;

public EntityCollection(Func<TDataContext, IQueryable<T>> query)

{

this.query = query;

Clear();

}

public void SubmitChanges()

{

db.SubmitChanges();

}

public IEnumerator IEnumerable.GetEnumerator()

{

return list.GetEnumerator();

}

public IEnumerator<T> GetEnumerator()

{

return list.GetEnumerator();

}

public void Add(T item)

{

this.db.GetTable<T>().InsertOnSubmit(item);

list.Add(item);

}

public void Clear()

{

DisposeContext(db);

db = (TDataContext)Activator.CreateInstance<TDataContext>();

list = query(db).ToList();

}

public bool Contains(T item)

{

return list.Contains(item);

}

public void CopyTo(T[] array, int arrayIndex)

{

return list.CopyTo(array, arrayIndex);

}

public void Remove(T item)

{

db.GetTable<T>().DeleteOnSubmit(item);

list.Remove(item);

}

public int Count

{

get

{

return list.Count;

}

}

public bool IsReadOnly

{

get

{

return false;

}

}

// Also implement IDisposable, which calls DisposeContext(db), which you implement.

}






Re: LINQ Project General dlinq - update

LubosSykora

hi,

i haven't tested yet but looks like nice solution! thanks!

regards

L