In Part 1: Generic Data Access Layer using ADO.NET Entity Framework of this series, I demonstrated how to generate a data model using the ADO.NET Entity Framework.
In this article, we will take a deeper look at what the ADO.NET Entity Framework has provided us and
how we can modify it to achieve a Generic Data Access Layer.
The Entity Framework creates a ObjectContext class for us. This class provides us
access to all the tables in the database and hence provides access to the
data.
The following code snippet is an example of how a DataContext class is created by the ADO.NET Entity Framework.
public
partial class
PublishingCompanyEntities :
ObjectContext
{
}
If you dig deeper into this class, you will see definitions like the following:
As shown in the screenshot above, the ObjectContext provides us with methods which
help us access the Database.
Now lets take a look at the entities. The Entity Framework creates partial classes
for each of the tables in the data model. These partial classes extend the
EntityObject class as shown below.
Below is the code for the Author entity.
[EdmEntityTypeAttribute(NamespaceName
= "PublishingCompanyModel", Name =
"Author")]
[Serializable()]
[DataContractAttribute(IsReference=true)]
public partial
class Author
: EntityObject
{
#region
Factory Method
///
<summary>
///
Create a new Author object.
///
</summary>
///
<param name="authorID">Initial
value of the AuthorID property.</param>
public
static Author CreateAuthor(global::System.Int32
authorID)
{
Author author =
new Author();
author.AuthorID = authorID;
return author;
}
#endregion
#region
Primitive Properties
///
<summary>
/// No
Metadata Documentation available.
///
</summary>
[EdmScalarPropertyAttribute(EntityKeyProperty=true,
IsNullable=false)]
[DataMemberAttribute()]
public global::System.Int32
AuthorID
{
get
{
return _AuthorID;
}
set
{
if (_AuthorID !=
value)
{
OnAuthorIDChanging(value);
ReportPropertyChanging("AuthorID");
_AuthorID = StructuralObject.SetValidValue(value);
ReportPropertyChanged("AuthorID");
OnAuthorIDChanged();
}
}
}
private global::System.Int32
_AuthorID;
partial void
OnAuthorIDChanging(global::System.Int32 value);
partial void
OnAuthorIDChanged();
///
<summary>
/// No
Metadata Documentation available.
///
</summary>
[EdmScalarPropertyAttribute(EntityKeyProperty=false,
IsNullable=true)]
[DataMemberAttribute()]
public global::System.String
FirstName
{
get
{
return _FirstName;
}
set
{
OnFirstNameChanging(value);
ReportPropertyChanging("FirstName");
_FirstName = StructuralObject.SetValidValue(value,
true);
ReportPropertyChanged("FirstName");
OnFirstNameChanged();
}
}
private global::System.String
_FirstName;
partial void
OnFirstNameChanging(global::System.String
value);
partial void
OnFirstNameChanged();
///
<summary>
/// No
Metadata Documentation available.
///
</summary>
[EdmScalarPropertyAttribute(EntityKeyProperty=false,
IsNullable=true)]
[DataMemberAttribute()]
public global::System.String
LastName
{
get
{
return _LastName;
}
set
{
OnLastNameChanging(value);
ReportPropertyChanging("LastName");
_LastName = StructuralObject.SetValidValue(value,
true);
ReportPropertyChanged("LastName");
OnLastNameChanged();
}
}
private global::System.String
_LastName;
partial void
OnLastNameChanging(global::System.String value);
partial void
OnLastNameChanged();
#endregion
#region
Navigation Properties
///
<summary>
/// No
Metadata Documentation available.
///
</summary>
[XmlIgnoreAttribute()]
[SoapIgnoreAttribute()]
[DataMemberAttribute()]
[EdmRelationshipNavigationPropertyAttribute("PublishingCompanyModel",
"FK_Article_Author",
"Article")]
public
EntityCollection<Article> Articles
{
get
{
return ((IEntityWithRelationships)this).RelationshipManager.GetRelatedCollection<Article>("PublishingCompanyModel.FK_Article_Author",
"Article");
}
set
{
if ((value
!= null))
{
((IEntityWithRelationships)this).RelationshipManager.InitializeRelatedCollection<Article>("PublishingCompanyModel.FK_Article_Author",
"Article", value);
}
}
}
///
<summary>
/// No
Metadata Documentation available.
///
</summary>
[XmlIgnoreAttribute()]
[SoapIgnoreAttribute()]
[DataMemberAttribute()]
[EdmRelationshipNavigationPropertyAttribute("PublishingCompanyModel",
"FK_Payroll_Author",
"Payroll")]
public
EntityCollection<Payroll> Payrolls
{
get
{
return ((IEntityWithRelationships)this).RelationshipManager.GetRelatedCollection<Payroll>("PublishingCompanyModel.FK_Payroll_Author",
"Payroll");
}
set
{
if ((value
!= null))
{
((IEntityWithRelationships)this).RelationshipManager.InitializeRelatedCollection<Payroll>("PublishingCompanyModel.FK_Payroll_Author",
"Payroll", value);
}
}
}
#endregion
}
Each partial class is decorated with attributes.
Let's take a look at these attributes.
EdmEntityTypeAttribute
Attribute that indicates that the class represents an entity type. Without this
attribute on top of the partial class, the class will not be recognised as an Entity Type.
Example of using this attribute is shown below:
[EdmEntityTypeAttribute(NamespaceName="PublishingCompanyModel", Name="Author")]
Serializable
Indicates that a class can be serialized. Apply the SerializableAttribute
attribute to a type to indicate that instances of this type can be serialized.
The common language runtime throws SerializationException if any type in the
graph of objects being serialized does not have the SerializableAttribute
attribute applied.
Example is given below :
[Serializable()]
DataContractAttribute
Specifies that the type defines or implements a data contract and is
serializable by a serializer, such as the DataContractSerializer. To make their
type serializable, type authors must define a data contract for their type.
Example is given below :
[DataContractAttribute(IsReference=true)]
Summary
In this part of this series, we saw how the data model and data entities are defined and created by the ADO.NET Data Entity Framework. Without understanding these internals, it is not possible to create a generic data access layer.