+++ title = "linqtosql" draft = false tags = [ "", "Users", "jefklak", "Downloads", "pages", "code", "csharp", "linqtosql" ] date = "2015-07-14" +++ # code:csharp >> Linqtosql Zie ook [MSDN LinqToSql pagina](https://msdn.microsoft.com/en-us/library/bb425822.aspx) ## Basic Principe is een **DataContext** object aanmaken waar je je connectionstring aan meegeeft (`Log` kan naar `Console.Out` ofzo). Vanaf dan via het context object werken: * `context.GetTable().Where(t ######> t.Property x).ToList()` om te queryen * bij deleten of wijzigen: `.Attach(entity)` en `.DeleteOnSubmit(entity)` * ... Modellen: annoteren met `[Table(Name######"tabelnaam")]`, kolommen met `[Column(Name"kolomnaam", IsPrimaryKey ###### true, IsDbGenerated true)]` Wijzigingen doorvoeren met `SubmitChanges()` door simpelweg properties van modellen te wijzigen, zoals een "echte" ER tool. ## Advanced #### ManyToOne relaties en domain driven design In het model: `[Association(ThisKey ###### "ReferenceId", IsForeignKey true)]` attribuut toevoegen. Als je een Fetch wil doen en associaties ook wenst op te halen moet je dit **altijd meegeven**: `new DataLoadOptions().LoadWith(t => t.AssociationProperty)`. Ook deze loadoptions meegeven aan de context. Indien dit overgeslagen wordt, zal bij een ToList in LINQ die property niet opgehaald worden. Dit is vervelend om elke keer mee te geven - kan ook generiek, bijvoorbeeld zo: ```csharp private static void AddLoadOptions(DataContext context) where T : class, new() { if (IsAssociation()) { var loadOps = new DataLoadOptions(); ((IAssociationModel)new T()).AssociationsToLoad(loadOps); context.LoadOptions = loadOps; } } private static bool IsAssociation() where T : class, new() { return typeof(IAssociationModel).IsAssignableFrom(typeof(T)); } ``` `AddLoadOptions` altijd aanroepen wanneer een fetch in een repository zou gebeuren. Dit zit er op de interface: ```csharp public interface IAssociationModel { IList AssocationsToAttach(); void AssociationsToLoad(DataLoadOptions loadOps); } ``` Zo kan iedere entiteit zijn eigen `LoadWith` oproepen. #### Transacties Gebruik `TransactionScope` object, aanmaken voor je iets doet en `.Complete()` of `.Dispose()` oproepen.

Om dit niet de helel tidj zelf te moeten beheren, complexiteit opbergen in een basis Repository klasse, zoiets: ```csharp using (var repo = Repository.Instance.Transactional()) { Fetch(); // ... Delete(); // ... } ``` om dan in de `Dispose()` de transactie te completen. De transactionele method maakt een scope aan. ## Compleet voorbeeld repository ```chsarp public class Repository : IRepository { private readonly string _ConnectionString; private DataContext _CurrentContext; private TransactionScope _TransactionScope; public Repository(string connectionString) { _ConnectionString = connectionString; } private Repository(Repository baseRepo) : this(baseRepo._ConnectionString) { _CurrentContext = CreateContext(); _TransactionScope = new TransactionScope(); } public static IRepository Instance { get; set; } private bool InTransaction { get { return _TransactionScope != null; } } public void Add(T entity) where T : class, new() { InContext(context => { var table = context.GetTable(); if (IsAssociation()) { foreach (var toAttach in ((IAssociationModel)entity).AssocationsToAttach()) { context.GetTable(toAttach.GetType()).Attach(toAttach); } } table.InsertOnSubmit(entity); }); } public void Add(IEnumerable entities) where T : class { InContext(context => context.GetTable().InsertAllOnSubmit(entities)); } public void CommitChanges(T entity) where T : class { InContext(context => { var entityTable = context.GetTable(); if (!InTransaction) { entityTable.Attach(entity); } context.Refresh(RefreshMode.KeepCurrentValues, entity); }); } public int Count(ICanModifyIQueryable queryModifier) where T : class, new() { return InContext(context => { AddLoadOptions(context); IQueryable list = context.GetTable(); list = queryModifier.ModifyForCount(list); return list.Count(); }); } public void Delete(T entity) where T : class { InContext(context => { var entityTable = context.GetTable(); if (!InTransaction) { entityTable.Attach(entity); } entityTable.DeleteOnSubmit(entity); }); } public void Dispose() { CompleteTransaction(); } public List Fetch() where T : class, new() { return InContext(context => { AddLoadOptions(context); return context.GetTable().ToList(); }); } public List FetchBy(Expression> whereClause) where T : class, new() { return InContext(context => { AddLoadOptions(context); return context.GetTable() .Where(whereClause) .ToList(); }); } public List FetchBy(ICanModifyIQueryable queryModifier) where T : class, new() { return InContext(context => { AddLoadOptions(context); IQueryable list = context.GetTable(); list = queryModifier.Modify(list); return list.ToList(); }); } public IRepository Transactional() { return new Repository(this); } private static void AddLoadOptions(DataContext context) where T : class, new() { if (IsAssociation()) { var loadOps = new DataLoadOptions(); ((IAssociationModel)new T()).AssociationsToLoad(loadOps); context.LoadOptions = loadOps; } } private static bool IsAssociation() where T : class, new() { return typeof(IAssociationModel).IsAssignableFrom(typeof(T)); } private void CompleteTransaction() { if (_CurrentContext ###### null || !InTransaction) { return; } try { _CurrentContext.SubmitChanges(); _TransactionScope.Complete(); } finally { _TransactionScope.Dispose(); _CurrentContext.Dispose(); _TransactionScope = null; _CurrentContext = null; } } private DataContext CreateContext() { return new DataContext(_ConnectionString) { Log = Console.Out }; } private void InContext(Action action) { InContext(context => { action(context); return true; }); } private T InContext(Func action) { var context = _CurrentContext; var newContext = false; if (context ###### null) { context = CreateContext(); newContext = true; } try { // context.Log = Console.Out; var value = action(context); if (newContext) { context.SubmitChanges(); } return value; } finally { if (newContext) { context.Dispose(); } } } } ```