Mapping a derived class to a table in Linq-to-SQL - linq-to-sql

I have an abstract base class for audit properties. For brevity say it has one property
Public MustInherit Class AbstractAuditableEntity
...
Public Property CreatedTime() As DateTimeOffset
...
End Class
And then my auditable domain objects inherit from this class
Public Class Source
Inherits AbstractAuditableEntity
...
Public Property SourceId() As String
...
End Class
I have the following table DDL to which I want to map my domain object "Source". Essentially the relationship between each (concrete) domain object and table is 1-1, with each table having the required audit column.
CREATE TABLE Source
(
SourceID VARCHAR(10) NOT NULL,
CreatedTime DATETIMEOFFSET(3) NOT NULL,
CONSTRAINT PK_Source PRIMARY KEY (SourceID))
GO
Using an external mapping file my first attempt to map the class to the table would foolishly be:
<?xml version="1.0" encoding="utf-8"?>
<Database Name="" xmlns="http://schemas.microsoft.com/linqtosql/mapping/2007">
<Table Name="Source" Member="Sources">
<Type Name ="Source">
<Column Name="SourceID" Member="SourceID" IsPrimaryKey="true" CanBeNull="false"/>
<Column Name="CreatedTime" Member="CreatedTime" />
</Type>
</Table>
</Database>
However this generates the following exception:
The column or association 'CreatedTime' in the mapping had no corresponding member in type 'Source'. Mapping members from above root type is not supported.
Within the context of my persistence layer I am not trying to represent an inheritance hierarchy as such, but within the context of my application I am simply using a base class to provided properties required by all my domain objects. With a lot of fiddling with my mapping file (including mapping the audit columns to the base AbstractAuditableEntity type) and reading around, I am unable to achieve what I perceive as quite a straighforward ORM task.
Any thoughts or suggestions would be most welcome!
Thanks

I'm guessing that you are trying to emulate auditing fields like Ruby on Rails updated_on, created_on. If so, here is how I accomplished something similar using this post as a starting point
http://weblogs.asp.net/stevesheldon/archive/2008/02/23/a-method-to-handle-audit-fields-using-linq-to-sql.aspx
I implemented an interface in the Models namespace like so:
public interface IAuditable
{
DateTime CreatedOn { get; set; }
string CreatedBy { get; set; }
DateTime? ChangedOn { get; set; }
string ChangedBy { get; set; }
}
And then extended the partial classes of the data entities that had these fields:
public partial class DataModelIWantToAudit : IAuditable
{
}
And then overrode SubmitChanges on the DataContext to check for the implementation of the interface with the magic of Linq OfType<>:
public override void SubmitChanges(ConflictMode failureMode)
{
//Updates
foreach (var updatedModel in GetChangeSet().Updates.OfType<IAuditable>())
{
updatedModel.ChangedOn = DateTime.Now;
updatedModel.ChangedBy = Membership.GetUser().UserName;
}
//Inserts
foreach (var insertedModel in GetChangeSet().Inserts.OfType<IAuditable>())
{
insertedModel.CreatedOn = DateTime.Now;
insertedModel.CreatedBy = Membership.GetUser().UserName;
}
base.SubmitChanges(failureMode);
}
Hope that helps!
-Kelly

Kelly showed a great sample of how to do it - but you've basically hit one of the limitations of Linq-to-SQL.
It works great if you database table map more or less 1:1 to your domain objects. But it's weak and causes a lot of extra work once this is no longer the case.
In such a case, as soon as you have domain object inheritance and other things that need to be mapped to database tables, you're best bet would be to check out ADO.NET Entity Framework instead. The EF is specifically designed to handle these things - if you ever think "I need to map my objects ......" then you should think EF! :-)
Granted, the current EF shipping in .NET 3.5 SP1 has its warts and annoyances, but the EF 4 that is part of the .NET 4.0 wave (which should ship before the end of this year 2009), should solve a great many of those warts!
Check out the ADO.NET Entity Framework team blog for some teasers of what EF4 will bring us all!
Marc

Related

How do I populate a Data Access Layer Model Efficiently?

I'm working on developing my first Data Driven Domain using Dependency Injection in ASP.net.
In my Data Access Layer if have created some domain data models, for example:
public class Company {
public Guid CompanyId { get; set; }
public string Name { get; set; }
}
public class Employee {
public Guid EmployeeId { get; set; }
public Guid CompanyId { get; set; }
public string Name { get; set; }
}
I have then developed an interface such as:
public interface ICompanyService {
IEnumerable<Model.Company> GetCompanies();
IEnumerable<Model.Employee> GetEmployees();
IEnumerable<Model.Employee> GetEmployees(Guid companyId);
}
In a separate module I have implemented this interface using Linq to Sql:
public class CompanyService : ICompanyService {
public IEnumerable<Model.Employee> GetEmployees();
{
return EmployeeDb
.OrderBy(e => e.Name)
.Select(e => e.ToDomainEntity())
.AsEnumerable();
}
}
Where ToDomainEntity() is implemented in the employee repository class as an extension method to the base entity class:
public Model.EmployeeToDomainEntity()
{
return new Model.Employee {
EmployeeId = this.EmployeeId,
CompanyId = this.CompanyId,
Name = this.Name
};
}
To this point, I have more or less followed the patterns as described in Mark Seeman's excellent book 'Dependency Injection in .NET' - and all works nicely.
I would like however to extend my basic models to also include key reference models, so the domain Employee class would become:
public class Employee {
public Guid EmployeeId { get; set; }
public Guid CompanyId { get; set; }
public Company { get; set; }
public string Name { get; set; }
}
and the ToDomainEntity() function would be extended to:
public Model.Employee ToDomainEntity()
{
return new Model.Employee {
EmployeeId = this.EmployeeId,
CompanyId = this.CompanyId,
Company = (this.Company == null) ? null : this.Company.ToDomainEntity()
Name = this.Name
};
}
I suspect that this might be 'bad practice' from a domain modelling point of view, but the problem I have encountered would also, I think, hold true if I were to develop a specific View Model to achieve the same purpose.
In essence, the problem I have run into is the speed/efficiency of populating the data models. If I use the ToDomainEntity() approach described above, Linq to Sql creates a separate SQL call to retrieve the data for each Employee's Company record. This, as you would expect, increases the time taken to evaluate the SQL expression quite considerably (from around 100ms to 7 seconds on our test database), particularly if the data tree is complex (as separate SQL calls are made to populate each node/sub-node of the tree).
If I create the data model 'inline...
public IEnumerable<Model.Employee> GetEmployees();
{
return EmployeeDb
.OrderBy(e => e.Name)
.Select(e => new Model.Employee {
EmployeeId = e.EmployeeId,
/* Other field mappings */
Company = new Model.Company {
CompanyId = e.Company.CompanyId,
/* Other field mappings */
}
}).AsEnumerable();
}
Linq to SQL produces a nice, tight SQL statement that natively uses the 'inner join' method to associate the Company with the Employee.
I have two questions:
1) Is it considered 'bad practice' to reference associated data classes from within a domain class object?
2) If this is the case, and a specific View Model is created for the purpose, what is the right way of populating the model using without having to resort to creating inline assignment blocks to build the expression tree?
Any help/advice would be much appreciated.
The problem is caused by having both data layer entities and domain layer entities and needing a mapping between the two. Although you can get this to work, this makes everything very complex, as you are already experiencing. You are making mappings between data and domain, and will soon add many more mappings for these same entities, because of performance reasons and because other business logic and presentation logic will need different data.
The only real solution is to ditch your data entities and create POCO model objects that can directly be serialized to your backend store (SQL server).
POCO entities is something that is supported in LINQ to SQL from day one, but I think it would be better to migrate to Entity Framework Code First.
When doing this, you can expose IQueryable<T> interfaces from your repositories (you currently called your repository ICompanyService, but a better name would be ICompanyRepository). This allows you to do efficient LINQ queries. When querying directly over a query provider you can prevent loading complete entities. For instance:
from employee in this.repository.GetEmployees()
where employee.Company.Name.StartWith(searchString)
select new
{
employee.Name,
employee.Company.Location
};
When working with IQueryable<T>, LINQ to SQL and Entity Framework will translate this to a very efficient SQL query that only returns the employe name and company location from the database with filtering inside the database (compared to do filtering in your .NET application when GetEmployees() returns an IEnumerable<T>).
You can ask Linq2Sql to preload certain entities (as opposed to lazy load them) using DataLoadOptions.LoadWith method see: http://msdn.microsoft.com/en-us/library/bb534268.aspx.
If you do this with the Company entity then I think Linq2Sql won't have to reach to the database to fetch it again.

EF 4.1 Code First doesn't create column for List<string>

I have been playing around quite a lot with EF4 Code First and I do love it. However, I cannot seem to sort this easy one out.
When trying to create something like this, no columns are created in my database:
public IList<String> Recievers { get; set; }
public List<String> RecieversTest { get; set; }
public virtual List<String> RecieversAnotherTest { get; set; }
public virtual ICollection<Int32> RecieversAnotherTest { get; set; }
Ive tried Annotations to map it to a different column name, I've tried IEnumerable and all sorts of other collections, but it refuses to create a column for it.
After an hour on google I found one that claims she has done it, but I'm starting to doubt that. Should it even be possible?
I can't really see why it just doesn't create a column and use JSON or CSV.
It can't be that rare, can it? In my case i just want to store a list of emails.
What am I missing? The project creates all other types without problems, and I've inspected the database to see how other properties I add to test with gets created, while these gets ignored.
So the problem must lie in some setting I'm missing or some configuration....
EF 4.1 RTW on an SQL Server 2008 db.
I have bad news for you. EF doesn't do anything like that. If you want any serialization and deserialization you must do it yourselves = you must expose and map property with serialized value:
private IList<String> _receivers;
// This will be skipped
public IList<String> Receivers
{
get
{
return _receivers;
}
set
{
_receivers = value;
}
}
// This will be mapped
public string ReceiversSer
{
get
{
return String.Join(";", _receivers);
}
set
{
_receivers = value.Split(';').ToList();
}
}
Now ReceiversSer will be mapped to a column in the database.
You can't have a column based on a collection/list of something. A column is a singular item such as public string Receiver.
If you are expecting EF CF to take your IList or List and make several Columns out of it you are correct in that it won't.
In EF CF you create lists in your Entity to represent a relationship to another table. An Order may have many Items in it. You would in this case have an Order class with a list to an OrderItem object.
You would then have an OrderItem class to describe the OrderItem table. This would then essentially represent the 1 to many relationship of Order and OrderItems.

PLINQO / LINQ-To-SQL - Generated Entity Self Save Method?

Hi I'm trying to create a basic data model / layer
The idea is to have:
Task task = TaskRepository.GetTask(2);
task.Description = "The task has changed";
task.Save();
Is this possible? I've tried the code below
Note: The TaskRepository.GetTask() methods detaches the Task entity.
I'd expect this to work, any ideas why it doesnt?
Thanks
public partial class Task
{
// Place custom code here.
public void Save()
{
using (TinyTaskDataContext db = new TinyTaskDataContext { Log = Console.Out })
{
db.Task.Attach(this);
db.SubmitChanges();
}
}
#region Metadata
// For more information about how to use the metadata class visit:
// http://www.plinqo.com/metadata.ashx
[CodeSmith.Data.Audit.Audit]
internal class Metadata
{
// WARNING: Only attributes inside of this class will be preserved.
public int TaskId { get; set; }
[Required]
public string Name { get; set; }
[Now(EntityState.New)]
[CodeSmith.Data.Audit.NotAudited]
public System.DateTime DateCreated { get; set; }
}
#endregion
}
Having done some reading I've realised I was implmenting the Repository pattern incorrectly. I should have been adding the Save method to the repository for conventions sake.
However, the actually problem I was having with regard to commiting the disconnected dataset was due to optimistic concurrency. The datacontext's job is to keep track of the state of it's entities. When entities become disconnected you loose that state.
I've found you need to add a timestamp field to the database table or I can set the UpdateCheck field on each column in my dbml file.
Here is some info about the UpdateCheck
Some useful links about disconnected Linq and plinqo
Great info on implementing the Repository pattern with LINQ
Short tutorial for implementing for updating and reattaching entities
Previously answer question
Rick Strahl on LINQ to SQL and attaching Entities
There is no need for this line (Task task = new Task();). The above should work although I've never seen it implemented in this manner. Have you thought about using the managers? Are you running into any runtime errors?
Thanks
-Blake Niemyjski

Linq - How to put common fields in a base class

I am trying to find a way so that I can push some common functionality into a base class for my Linq to SQL processing. I have two fields (ID and InsertUpdateOperID) that are common to most but not all of my tables. In my first go around I created a class called BaseEntity that had these fields. Unfortunately all I accomplished was hiding from the values in the .designer.cs file. I found an example of how to accomplish what I wanted In order to get around this (http://www.joe-stevens.com/2009/07/01/linq-to-sql-set-inheritance-modifiers-with-sqlmetal/). As per this article, I modifed the DBML file so that I could add the override modifier to the ID and InsertUpdateOperID properties on the tables that contained these two fields.
The net result of this was that the .designer.cs file added the override qualifier where I wanted it. This enabled me to create my BaseEntity class. Where I defined the ID field and the InsertUpdateOperID field as:
public virtual int ID { get; set; }
public virtual int InsertUpdateOperID { get; set; }
Doing this seemed to work fine.
The problem for me is that I hate the idea of modifying generated code. Can anyone suggest a way for me to put common fields and methods that act on those common fields in a base class so that I could accomplish what I want without modifying the generated .dbml?
Thanks
I'm facing the same problem today (wow, it's 1.5 years after your post), and struggled out a solution, so far it's good for me.
in the base class:
public virtual int __ID
{
get
{
PropertyInfo pi = this.GetType().GetProperty("ID");
int id = (int)pi.GetValue(this, new object[] {});
return id;
}
set
{
PropertyInfo pi = this.GetType().GetProperty("ID");
pi.SetValue(this, value, new object[] { });
}
}
This looks quite voilent, but it works!
Notice the __ before ID, because there is alread ID and _ID in the auto generated codes. As it's totally a new third way to access ID, no "override" is needed.
And if you need, you can use the __ID in or via your base class.

Return plain objects in entity framework for serialization

I have been trying out both Linq to Sql and EF in my ASP.NET MVC application. After switching to EF I realized my XML/JSON serialization output has extra cruft.
XML:
<Test xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<EntityKey>
<EntitySetName>Persons</EntitySetName>
<EntityContainerName>PersonEntities</EntityContainerName>
<EntityKeyValues>
<EntityKeyMember>
<Key>Id</Key>
<Value xsi:type="xsd:int">1</Value>
</EntityKeyMember>
</EntityKeyValues>
</EntityKey>
<Id>1</Id>
<Name>John</Name>
</Test>
JSON:
{"Id":1,"Name":"John","EntityState":2,"EntityKey"{"EntitySetName":"Persons","EntityContainerName":"PersonEntities","EntityKeyValues":[{"Key":"Id","Value":1}],"IsTemporary":false}}
Instead I would just like my output to be:
{"Id":1, "Name":"John"}
My EF query to retrieve the object is:
Tests.First(t => t.Id == testId);
You can shape the JSON result in your controller like this:
public JsonResult Person(int id)
{
var person = PersonRepository.FindByID(id);
var result = new { Id = person.Id, Name = person.Name };
return Json(result);
}
This will limit the DTO which is serialized to contain only the values you want.
Edit:
As a paritial answer to your comment question; you can create a simpler PersonViewModel class (DTO) that you can map the properties to. As John Saunders mentioned in his answer Automapper is a nice way to simplify the copying of the property values out of the EF Person instance:
The modified Action method may look like this:
public JsonResult Person(int id)
{
var person = PersonRepository.FindByID(id);
var dto = Mapper.Map<Person, PersonViewModel>(person);
return Json(dto);
}
The only other option I can think of is to use reflection to modify the DataMemberAttributes on the Person entity to suppress the EntityKey property.
Another approach to work around this is to use the JavascriptSerializer's ScriptIgnore attribute and create a partial class for the object in question, new'ing up the EntityKey, EntityState properties and adding a ScriptIgnore attribute to them:
public partial class Person
{
[ScriptIgnore]
public new System.Data.EntityKey EntityKey { get; set; }
[ScriptIgnore]
public new System.Data.EntityState EntityState { get; set; }
}
When the Person class is serialized via JavascriptSerializer, it will ignore those properties. However, this would not be practical because EF uses the state info to keep track of objects and this would wreak havoc.
If there were a way to dynamically add properties, it would eliminate the need to override those properties just to add a [ScriptIgnore] attribute. But, since there is no way to dynamically add attributes, this solution may not be that useful.
So far, the best technique I've found involves code generation. I did this on one project that was using the Service Factory, but you could do the same "by hand" using T4 Text templates directly.
Also, keep an eye on AutoMapper. It's still new enough that I consider it to be emerging technology, but I'm hoping it will emerge soon!