Painless use of View in Entity Framework 4 - vb.net

I'm creating a webform vb.net project in visual studio 2012.
I am also using Entity Framework for managing my objects.
The big pain is caused by a View in my database, which I am forced to use.
I can retrieve the objects from this view with this class:
Imports System.ComponentModel.DataAnnotations
Public Class C
<Key, StringLength(6), Display(name:="C")> _
Public Property IDC() As String
<Display(Name:="Descrizione"), StringLength(255)> _
Public Property Descrizione() As String
End Class
Now I would like to create a brand new model called "S". Every object of type S should refer to a object, of type C, therefore my code is:
Imports System.ComponentModel.DataAnnotations
Public Class S
<Key, Display(name:="Id")> _
Public Property SID() As Integer
<Required, StringLength(255)>
Public Property Descrizione() As String
Public Overridable Property Commessa() As Commessa
End Class
Unfortunately, when I try to apply the migration, the process fails because tries to modify the View to enforce a contraint:
ALTER TABLE [dbo].[S] ADD CONSTRAINT [FK_dbo.Ss_dbo.cs_C_IDC] FOREIGN KEY ([C_IDC]) REFERENCES [dbo].[c] ([IDC])
The migration code is:
Public Overrides Sub Up()
CreateTable(
"dbo.Ss",
Function(c) New With
{
.SID = c.Int(nullable := False, identity := True),
.Descrizione = c.String(nullable := False, maxLength := 255),
.C_IDC = c.String(maxLength := 6)
}) _
.PrimaryKey(Function(t) t.SID) _
.ForeignKey("dbo.c", Function(t) t.C_IDC) _
.Index(Function(t) t.C_IDC)
End Sub
In the context class the correct View is defined:
Protected Overrides Sub OnModelCreating(ByVal modelBuilder As DbModelBuilder)
modelBuilder.Entity(Of C)().ToTable("c")
End Sub
Googling this problem around, I "think" a possibility is to turn off the cascade delete feature, but even with:
modelBuilder.Entity(Of S).HasRequired(Function(c) c.C).WithMany.WillCascadeOnDelete(False)
the migration tries to modify the View. (Is the code above correct?)
Is it possible to use the View in the Entity Framework in this way?
How can I link objects from the models I am going to create to elements in this View?
Is Entity Framework a reasonable approach in this scenario?
Thanks!

Code First Migrations is designed to automatically manage your database. If your DB has restrictions that make complete automation impossible (like Views), you could :
Disable Code First Migrations
Let EF generate a db update script for you, but only apply the parts you want
There is some great general info on using Code First Migrations with an existing DB on Ralph Lavelle's blog.

Related

How does one override the default SQL migration generator?

I'm attempting to override the default behavior of the SQL migrations generator so that I may specify a custom foreign key constraint name, as discussed here. I've wired up the configuration as advised.
Unfortunately, however, it's not going so well.
A quick logging statement reveals that the GetFkName() function is never hit.
I tried an alternate configuration construct, as discussed here and here, but I'm getting this error when I attempt to generate a migration:
More than one migrations configuration type was found in the assembly 'ConsoleApp1'. Specify the name of the one to use.
I find this result a bit odd, as I have only one configuration class, one SQL generation class, and one context class (the code below doesn't reflect this, but I commented out the extras for my actual tests). Specifying the configuration type on the command line, as indicated here, errors with this:
System.InvalidOperationException: The type 'ConsoleApp1.Db.CustomDbConfiguration2' does not inherit from 'System.Data.Entity.DbConfiguration'. Entity Framework code-based configuration classes must inherit from 'System.Data.Entity.DbConfiguration'.
All of this brings us back here, then, which doesn't work for the aforementioned reason (GetFkName() never gets hit). So it seems I'm chasing my tail (didn't know I had one until today).
What should I do to get this override to work correctly?
Configuration
Imports System.Data.Entity
Imports System.Data.Entity.Migrations
Imports System.Data.Entity.SqlServer
Namespace Db
Friend Class CustomDbConfiguration
Inherits DbConfiguration
Public Sub New()
Me.SetMigrationSqlGenerator(SqlProviderServices.ProviderInvariantName, Function() New CustomSqlGenerator)
End Sub
End Class
Friend Class CustomDbConfiguration2
Inherits DbMigrationsConfiguration(Of Context)
Public Sub New()
Me.SetSqlGenerator(SqlProviderServices.ProviderInvariantName, New CustomSqlGenerator2(Me.GetSqlGenerator(SqlProviderServices.ProviderInvariantName)))
Me.ContextType = GetType(Context)
End Sub
End Class
End Namespace
SQL Generator
Imports System.Data.Entity.Migrations.Model
Imports System.Data.Entity.Migrations.Sql
Imports System.Data.Entity.SqlServer
Namespace Db
Friend Class CustomSqlGenerator
Inherits SqlServerMigrationSqlGenerator
Protected Overrides Sub Generate(AddForeignKeyOperation As AddForeignKeyOperation)
AddForeignKeyOperation.Name = GetFkName(AddForeignKeyOperation.PrincipalTable, AddForeignKeyOperation.DependentTable, AddForeignKeyOperation.DependentColumns.ToArray())
MyBase.Generate(AddForeignKeyOperation)
End Sub
Protected Overrides Sub Generate(DropForeignKeyOperation As DropForeignKeyOperation)
DropForeignKeyOperation.Name = GetFkName(DropForeignKeyOperation.PrincipalTable, DropForeignKeyOperation.DependentTable, DropForeignKeyOperation.DependentColumns.ToArray())
MyBase.Generate(DropForeignKeyOperation)
End Sub
Private Shared Function GetFkName(PrimaryKeyTable As String, ForeignKeyTable As String, ParamArray ForeignTableFields As String()) As String
IO.File.WriteAllText("D:\Logs\FkNameTest.log", $"{Now.ToString}{vbCrLf}")
Return $"FK_{ForeignKeyTable}_{PrimaryKeyTable}"
End Function
End Class
Friend Class CustomSqlGenerator2
Inherits MigrationSqlGenerator
Public Sub New(Generator As MigrationSqlGenerator)
Me.Generator = Generator
End Sub
Public Overrides Function Generate(MigrationOperations As IEnumerable(Of MigrationOperation), ProviderManifestToken As String) As IEnumerable(Of MigrationStatement)
Return Me.Generator.Generate(MigrationOperations, ProviderManifestToken)
End Function
Private ReadOnly Generator As MigrationSqlGenerator
End Class
End Namespace
Context
Imports System.Data.Common
Imports System.Data.Entity
Imports System.Data.SqlClient
Imports System.Reflection
Namespace Db
<DbConfigurationType(GetType(CustomDbConfiguration2))>
Friend Class Context
Inherits DbContext
Public Sub New()
MyBase.New(DbConnection.ConnectionString)
End Sub
Private Sub New(Connection As DbConnection)
MyBase.New(Connection, True)
Database.SetInitializer(New CreateDatabaseIfNotExists(Of Context))
Database.SetInitializer(New MigrateDatabaseToLatestVersion(Of Context, Migrations.Configuration))
Me.Database.Initialize(False)
End Sub
Public Shared Function Create() As Context
Return New Context(DbConnection)
End Function
Private Shared ReadOnly Property DbConnection As SqlConnection
Get
Return New SqlConnection(Utils.DbConnectionString)
End Get
End Property
Protected Overrides Sub OnModelCreating(Builder As DbModelBuilder)
Builder.Configurations.AddFromAssembly(Assembly.GetExecutingAssembly)
MyBase.OnModelCreating(Builder)
End Sub
Public Property Documents As DbSet(Of Document)
Public Property Sections As DbSet(Of Section)
End Class
End Namespace
Disclaimer: I haven't coded in VB for many years, these code examples are my feeble attempt to translate my working example in C# into OPs native VB. Please feel free to update my syntax ;)
You can manually edit the migration scripts to specify a custom name for each ForeignKey by specifying a value for the optional Name parameter in the call to Tablebuilder.ForeignKey as part of a create table statement:
CreateTable(
"dbo.CorporationVariety",
Function(c) New With
{
.Id = c.Int(nullable: false, identity:= true),
.CorporationId = c.Int(nullable:= false),
.VarietyId = c.Int(nullable:= false),
}) _
.PrimaryKey(Function(t) t.Id)
.ForeignKey("dbo.Corporation", Function(t) t.CorporationId, name := "FKCorporatationCorporationVarietyCorporationId")
.ForeignKey("dbo.Variety", Function(t) t.VarietyId, name := "FKVarietyCorporationVarietyVarietyId")
.Index(Function(t) t.CorporationId)
.Index(Function(t) t.VarietyId)
Or as part of a DbMigration.AddForeignKey statement:
AddForeignKey("dbo.CorporationVariety", "CorporationId", "dbo.Corporation", name := "FKCorporatationCorporationVarietyCorporationId")
AddForeignKey("dbo.CorporationVariety", "VarietyId", "dbo.Variety", name := "FKVarietyCorporationVarietyVarietyId")
If you have a lot of keys in your Model, and you want to implement a specific convention, (as in a standard rule or sequence of code that you want to apply in given scenarios) across all keys, then Normally the first place to look for a solution is EF Code First Conventions.
Unfortunately, there is neither a standard convention that can help you here nor can you define a custom name for a foreign key using fluent notation...
Normally we would go ahead and create a Custom Code First Convention to define your custom logic, this works in generally 2 ways:
Your convention executes standard configuration via Fluent Notation
we already noted that this option is not available to us...
Your convention logic stores custom metadata to the model via annotations
Primary and Foreign keys seem to be an anomaly in the EF Code First Runtime, there does not seem to be a way to easily access the annotations from the associations even though they are relatively easy to define.
I was surprised to find this and stumbled across this post that further confirms this: https://stackoverflow.com/a/54369685/1690217
Update I started this post assuming that Conventions was the right way to go, because I use it for many other customisations that I've needed to apply over the years. If you are looking to implement other similar types of customisations, look to Conventions first.
We can still easily override the standard VisualBasicMigrationCodeGenerator that generates the migration code files, so lets jump straight into that.
coapply to custom name for your ForeignKey and then implement a custom MigrationCodeGenerator to process the output from your convention.
Create a custom VisualBasicMigrationCodeGenerator
Register the Code Generator so that it is used by EF to generate the next migration
NOTE: This will not force existing keys in your database to be renamed. To do that you would need to force each key to be dropped and re-added back. For a large model Consider using a T4 template to create custom once-off migration logic to achieve this, once the above steps are in place.
Think of your Custom VisualBasicMigrationCodeGenerator as your personal EF code first sour dough culture, you can share this and re-use it for every new application, adding new functionality and improvements with each iteration. But Conventions are the configuration options that you may not want in every project, (which is why using _Conventions_ for OPs solution was my first direction.)
1. Create a custom VisualBasicMigrationCodeGenerator
Create a new class that inherits from the EF VisualBasicMigrationCodeGenerator, the minimal we need to do is override the AddForeignKeyOperation and modify the Name of the key and call the base implementation. This will affect all new keys added to the model.
To target keys added as part of CreateTable we will have to override GenerateInline(AddForeignKeyOperation...), however the base implemention (in the C# Generator...) doesn't obey the custom Name so instead we have to replace the implementation entirely.
When doing this, goto the EF project on GitHub and start with the original implementation, then inject your customizations as needed.
Please excuse this C#, I didn't have time to translate it, it does generate the correct VB code though ;)
public class CustomVBMigrationCodeGenerator : System.Data.Entity.Migrations.Design.VisualBasicMigrationCodeGenerator
{
protected override void Generate(AddForeignKeyOperation addForeignKeyOperation, IndentedTextWriter writer)
{
ApplyCustomFKName(addForeignKeyOperation);
base.Generate(addForeignKeyOperation, writer);
}
private void ApplyCustomFKName(ForeignKeyOperation operation)
{
// expecting FK without scheme or underscores: "FK{DependentTable}{PrincipalTable}{FKField}"
operation.Name = $"FK{StripSchemeFromName(operation.DependentTable)}{StripSchemeFromName(operation.PrincipalTable)}{String.Join("", operation.DependentColumns)}";
}
private string StripSchemeFromName(string dbObjectName)
{
return dbObjectName.Split(new[] { '.' }, 2).Last();
}
/// <summary>
/// Generates code to perform an <see cref="AddForeignKeyOperation" /> as part of a <see cref="CreateTableOperation" />.
/// </summary>
/// <param name="addForeignKeyOperation"> The operation to generate code for. </param>
/// <param name="writer"> Text writer to add the generated code to. </param>
protected virtual void GenerateInline(AddForeignKeyOperation addForeignKeyOperation, IndentedTextWriter writer)
{
// sourced from https://github.com/aspnet/EntityFramework6/blob/master/src/EntityFramework/Migrations/Design/VisualBasicMigrationCodeGenerator.cs
Check.NotNull(addForeignKeyOperation, "addForeignKeyOperation");
Check.NotNull(writer, "writer");
writer.WriteLine(" _");
writer.Write(".ForeignKey(" + Quote(addForeignKeyOperation.PrincipalTable) + ", ");
Generate(addForeignKeyOperation.DependentColumns, writer);
// Our Custom logic
ApplyCustomFKName(addForeignKeyOperation);
// Insert our custom name if provided
if (!addForeignKeyOperation.HasDefaultName)
{
writer.Write(", name := " + Quote(addForeignKeyOperation.Name));
}
if (addForeignKeyOperation.CascadeDelete)
{
writer.Write(", cascadeDelete := True");
}
writer.Write(")");
}
}
2. Register the Code Generator so that it is used by EF to generate the next migration
Locate Configuration.vb in your project, int the constructor set the CodeGenerator to an instance of your CustomVBMigrationCodeGenerator :
Public Sub New()
AutomaticMigrationsEnabled = false
CodeGenerator = new CustomVBMigrationCodeGenerator()
End Sub
Now execute the add-migration to generate a new migration you will see you new custom name defined in the migration script.
You may be required to similarly override the Generate(DropForeignKeyOperation...) methods as well if you need to downgrade from this configuration _or_ if alter table commands require the key to be dropped first.

MVC 5 - EF 6.1 Scaffolding fails when inheriting from IdentityDbContext and IdentityUser

I have been struggling with the new ASP.NET Identity trying to extend it to do my next web application, I have opend a new empty web project in Visual Studio 2013 Profissional, and added MVC 5 assembly as usual.
I have write the following in VB.NET (Code-First)
Imports System.ComponentModel.DataAnnotations
Imports System.ComponentModel.DataAnnotations.Schema
Imports Microsoft.AspNet.Identity.EntityFramework
Imports System.Data.Entity
Partial Public Class MyAppContext
Inherits IdentityDbContext(Of User)
Public Sub New()
MyBase.New("ConnStr")
End Sub
Public Overridable Property Items As DbSet(Of Item)
End Class
Partial Public Class User
Inherits IdentityUser
<Required>
Public Property Name As String
Public Property Items As ICollection(Of Item) = New HashSet(Of Item)
End Class
Partial Public Class Item
<Key> <DatabaseGenerated(DatabaseGeneratedOption.Identity)>
Public Property ID As Integer
<Required>
Public Property Name As String
<Required>
Public Property UserID As String
<ForeignKey("UserID")>
Public Overridable Property User As User
End Class
I think the code is very straight-forward, i am trying to create "User" class that inherit from "IdentityUser" and adding a one-to-many relationship with another class called "Item", and of course I have to extend the generic class "IdentityDbContext(Of User)".
Then I want to add a controller with the views for my "User" and "Item" classes using the scaffolding option "MVC 5 Controller with views, using Entity Framework".
Error There was an error running the selected code generator: 'Value cannot be null. Parameter name: codeType'
I want you to know that this is a clean setup for visual studio 2013, a clean project, and also the scaffolding works very good for the current model without the Identity inheritance thing.
Please let me know if you have successfully reproduce the problem on your machines.
I wanted to let you know that after i have converted the exact code to C# it worked!...
It seems that this is a vb.net related problem (something with the built-in t4 templetes).
So this is a bug, and i will assume this is the answer.
If somebody found a workaround for this, please post and I will accept it as the answer.

how to add ConcurrencyCheck with data annotation while doing database first without modifying the designer?

this is the class generated by the designer;
Partial Public Class fredTest
Public Property id As Integer
Public Property data As String
Public Property version As Integer
End Class
I'm trying to add the concurrency check by doing this;
<MetadataType(GetType(fredTestMeta))>
Partial Public Class fredTest
End Class
Public Class fredTestMeta
<ConcurrencyCheck>
Public Property version As Integer
End Class
and it doesn't work.
concurrency check does work if I use the designer to set it to fixed.
is it possible do make it work without playing with the designer?
If you are doing database first the concurrency needs to be set in the edmx file and this is what the designer does.

Dependency Injection with Entity Framework 5 Database First. Getting Started?

I am looking at creating a VB.NET 11 WPF MVVM application using Entity Framework 5 and Database First (Connecting to SQL Server 2008 R2).
I have chosen Database First, as I am migrating an existing solution to WPF MVVM, where the database already exists of course.
I'd like to begin using Dependency Injection so I can Unit Test as much of my code as possible.
I don't seem to be able to find a clear and concise walk-through of how to go about using Dependency Injection with EF DB-First, and in particular with vb.net. Although even a C# example would be fine I'm sure.
What I'd really like is a simple step by step guide explaining how to setup the solution, how to setup each part ready for Dependency Injection etc, but these seem hard to come by.
So far, I've created the Solution and it's Projects, as follows;
DBAccess - This houses nothing but my .edmx file, and a small mod to be able to supply the ConnectionString to the constructor.
DBControl - This houses the various classes which I use to provide a layer between my EDMX and my ViewModels. Specifically, I'm filling Complex Types (Which I have created using the designer) here for displaying "Friendlier" data via the UI, as well as converting these "Friendly" Complex Types to the mapped entities for saving / Updating. I have one class per table in my database. Each with two "FetchFriendlyRecords" methods (One accepts Filters) and an "AddUpdateFriendlyRecord" method. I have created an Interface for each class. Each class accepts a DbContext in it's constructor, and I'm simply passing my DBContext from the DBAccess Project.
MainUI - This houses my MVVM layers, and references each class in the DBControl Project in order to provide DataBinding etc.
I've seen suggested that, instead of spending time writing a complex solution to be able to unit test with EF, it's simpler to create a firm mock database with test data populated, and simply point the code at the mock database, rather than the live one. However, I'd prefer to be able to create an in memory solution that would run without any need to hit SQL Server at all.
Any help would be great, including telling me if I'm going about this all wrong!!
Update:
I have taken the solution provided by Paul Kirby below, and created a "Sort of" Repository Pattern I believe.
I created an interface;
Public Interface IFriendlyRepository(Of T)
ReadOnly Property FriendlyRecords As ObservableCollection(Of T)
Function GetFilteredFriendlyRecords(predicates As List(of Func(Of T, Boolean))) As ObservableCollection(Of T)
Function AddEditFriendlyRecord(ByVal RecordToSave As T) As EntityException
Sub SaveData()
End Interface
I then implemented this interface on a class by class basis;
Namespace Repositories
Public Class clsCurrenciesRepository
Implements Interfaces.IFriendlyRepository(Of CriticalPathDB.FriendlyCurrencies)
Private _DBContext As CriticalPathEntities 'The Data Context
Public Sub New(ByVal Context As DbContext)
_DBContext = Context
End Sub
Public ReadOnly Property FriendlyRecords As ObservableCollection(Of FriendlyCurrencies) Implements Interfaces.IFriendlyRepository(Of CriticalPathDB.FriendlyCurrencies).FriendlyRecords
Get
' We need to convert the results of a Linq to SQL stored procedure to a list,
' otherwise we get an error stating that the query cannot be enumerated twice!
Dim Query = (From Currencies In _DBContext.Currencies.ToList
Group Join CreationUsers In _DBContext.Users.ToList
On Currencies.CreationUserCode Equals CreationUsers.User_Code Into JoinedCreationUsers = Group
From CreationUsers In JoinedCreationUsers.DefaultIfEmpty
Group Join UpdateUsers In _DBContext.Users.ToList
On Currencies.LastUpdateUserCode Equals UpdateUsers.User_Code Into JoinedUpdateUsers = Group
From UpdateUsers In JoinedUpdateUsers.DefaultIfEmpty
Where (Currencies.Deleted = False Or Currencies.Deleted Is Nothing)
Order By Currencies.NAME
Select New FriendlyCurrencies With {.Currency_Code = Currencies.Currency_Code,
.NAME = Currencies.NAME,
.Rate = Currencies.Rate,
.CreatedBy = If(Currencies.CreationUserCode Is Nothing, "", CreationUsers.First_Name & " " & CreationUsers.Last_Name),
.CreationDate = Currencies.CreationDate,
.CreationUserCode = Currencies.CreationUserCode,
.Deleted = Currencies.Deleted,
.LastUpdateDate = Currencies.LastUpdateDate,
.LastUpdatedBy = If(Currencies.LastUpdateUserCode Is Nothing, "", UpdateUsers.First_Name & " " & UpdateUsers.Last_Name),
.LastUpdateUserCode = Currencies.LastUpdateUserCode}).ToList
Return New ObservableCollection(Of FriendlyCurrencies)(Query)
End Get
End Property
Public Function GetFilteredFriendlyRecords(predicates As List(of Func(Of FriendlyCurrencies, Boolean))) As ObservableCollection(Of FriendlyCurrencies) Implements Interfaces.IFriendlyRepository(Of CriticalPathDB.FriendlyCurrencies).GetFilteredFriendlyRecords
Dim ReturnQuery = FriendlyRecords.ToList
For Each Predicate As Func(Of FriendlyCurrencies, Boolean) In predicates
If Predicate IsNot Nothing Then
ReturnQuery = ReturnQuery.Where(Predicate).ToList
End If
Next
Return New ObservableCollection(Of FriendlyCurrencies)(ReturnQuery)
End Function
Public Function AddEditFriendlyRecord(ByVal RecordToSave As FriendlyCurrencies) As EntityException Implements Interfaces.IFriendlyRepository(Of CriticalPathDB.FriendlyCurrencies).AddEditFriendlyRecord
Dim dbCurrency As New Currency
' Check if this Staff Member Exists
Dim query = From c In _DBContext.Currencies
Where c.Currency_Code = RecordToSave.Currency_Code
Select c
' If Asset exists, then edit.
If query.Count > 0 Then
dbCurrency = query.FirstOrDefault
Else
'Do Nothing
End If
dbCurrency.Currency_Code = RecordToSave.Currency_Code
dbCurrency.NAME = RecordToSave.NAME
dbCurrency.CreationDate = RecordToSave.CreationDate
dbCurrency.CreationUserCode = RecordToSave.CreationUserCode
dbCurrency.LastUpdateDate = RecordToSave.LastUpdateDate
dbCurrency.LastUpdateUserCode = RecordToSave.LastUpdateUserCode
dbCurrency.Deleted = RecordToSave.Deleted
' Save Asset Object to Database
If query.Count > 0 Then
' If Asset exists, then edit.
Try
'_dbContext.SaveChanges 'We could save here but it's generally bad practice
Catch ex As EntityException
Return ex
End Try
Else
Try
_DBContext.Currencies.Add(dbCurrency)
'_dbContext.SaveChanges 'We could save here but it's generally bad practice
Catch ex As EntityException
Return ex
End Try
End If
Return Nothing
End Function
Public Sub SaveData() Implements Interfaces.IFriendlyRepository(Of CriticalPathDB.FriendlyCurrencies).SaveData
_DBContext.SaveChanges()
End Sub
End Class
End Namespace
I used constructor injection to insert the dbContext into the class.
I had hoped to be able to mock up a fake dbContext using my existing context and the "Effort" Unit Testing Tool.
However, I don't seem to be able to get this to work.
In the interim, in my Unit Test Project, I am dropping (If it already exists) and creating an empty test database, with the SQLCMD command, using the same schema as my live database.
I then create a dbContext referencing the Test Database, populate it with test data, and test against this.
As a note, I will be refactoring my "Add/Edit" method to work with an actual base Entity, rather than my "Friendly" complex version, this was the simplest method at the time.
If you're working DB-first, here's what I would suggest.
Open your .edmx file, right click on any blank space and choose "Add Code Generation Item"
In the "Online Templates" area, search for "EF 5.x DbContext Generator for VB".
Give the .tt file a name, hit add. This will change the way your .edmx file generates the backing code so that your entities are all POCO, which simplifies testing overall by keeping your main logic disconnected from EF.
After you've got that done, you probably want to look into something like the Unit of Work pattern. Here's a quick code example, I'll explain it after.
public interface IUnitOfWork
{
IDbSet<Location> Locations { get; }
void Commit();
}
public class EFUnitOfWork : IUnitOfWork
{
private readonly YourGeneratedDbContext _context;
public EFUnitOfWork(string connectionString)
{
_context = new YourGeneratedDbContext();
}
public IDbSet<Location> Locations
{
get { return _context.Locations; }
}
public void Commit()
{
_context.SaveChanges();
}
}
This is a basic unit of work that exposes some list of Locations as an example (sorry that it's in C# but I don't know VB well).
Notice that it is exposing IDbSet objects - this is where the magic comes in. If in your DBAccess project, you use this unit of work or a repository pattern to hide EF, and because it implements an interface and is returning IDbSet objects, anywhere that needs your data can have this IUnitOfWork constructor injected with DI, and replaced with a mocked version that returns mock IDbSet objects (they're just IQueryables in the end) when you need to unit test.
You may find that with the POCO generation in that new template, you can even do away with a lot of the work you're doing in your DBControl project.
Anyway that's just some basic stuff in terms of positioning your project for optimal unit testing and DI.

DisplayName DataAnnotations not working in WinForms 3.5 DataGridView

Ok, I'm completely at a loss here. I've used DataAnnotations attribute DisplayName successfully using MVC model binding, and even with WPF/Silverlight model binding and of course it works just fine, but now I'm on a project that I'm forced to use VB.NET 3.5 WinForms.
I have a Linq2Sql model and I created a partial class for one of my classes and included a MetadataType attribute to point to a metadata class. I added a DisplayName attribute to a property in the metadata class. I then bind my datagridview with an IQueryable(Of mydatatype), but the column name in the grid is the Property's name and not the DisplayName.
Am I missing something? Is there something else I need to do to get the datagridview to use the DisplayName?
In my Model class:
Imports System.ComponentModel
Imports System.ComponentModel.DataAnnotations
<MetadataType(GetType(vwREVIEW_ECRMetadata))> _
Partial Class vwREVIEW_ECR
Public Sub TestMethod()
End Sub
End Class
Public Class vwREVIEW_ECRMetadata
Private _ECRNumber As String
<DisplayName("ECR #")> _
Public Property ECRNumber() As String
Get
Return _ECRNumber
End Get
Set(ByVal value As String)
_ECRNumber = value
End Set
End Property
End Class
In my Repository class:
Public Function GetAllECRsForLookup() As IQueryable(Of vwREVIEW_ECR)
Return db.vwREVIEW_ECRs
End Function
In my Presenter class:
Public Sub GetData()
view.FillData(model.GetFilteredECRsForLookup())
End Sub
In my View:
Public Sub FillData(ByVal data As System.Linq.IQueryable(Of vwREVIEW_ECR)) Implements ILookupECRView.FillData
Me.uxECRData.DataSource = data
End Sub
Any help would be greatly appreciated! Thanks
Ok, so I found a solution to my problem. Didn't even think about it this way, but in ASP.NET & WPF, you get this behavior becuase of model binding behavior built in. WinForms has databinding as well, but isn't just there for your. Though I could've "bound" my datagridview to my linq2sql generated object in the runtime, which would've accomplished what I needed, I needed to do this at design time, so instead, I modified my MVP to use ViewModels where needed, and bind the datagrid to that object at runtime to get my column names to look the way I want. The ViewModel is hooked up to the model and can pass the real values to it.
I based this approach on this blog, though I didn't fully implement what he did:
http://aviadezra.blogspot.com/2009/08/mvp-mvvm-winforms-data-binding.html