I've got a many-to-many relationship set up via AutoMapping. Now, the save and updates work fine as expected, however the DiscountGroups are not being loaded in DiscountDay when I get the entities afterwards. I cannot for the life of me work out why the _discountGroups list is always empty, even though it's all correct in the database.
I've seen suggestions about using ISet rather than IList however it doesn't seem to make any difference in my case, neiter does using
.Not.LazyLoad()
in the mapping. Removing AsBag() and AsSet() also makes no difference.
The Entities
public class DiscountDay
{
public virtual DayOfWeek DayOfWeek { get; set; }
public virtual Discount Discount { get; set; }
private readonly IList<DiscountGroup> _discountGroups = new List<DiscountGroup>();
public virtual IEnumerable<DiscountGroup> DiscountGroups
{
get { return _discountGroups; }
set { }
}
}
public class DiscountGroup
{
public virtual string Name { get; set; }
private readonly IList<DiscountDay> _discountDay = new List<DiscountDay>();
public virtual IEnumerable<DiscountDay> DiscountDay
{
get { return _discountDay; }
}
}
The Mappings
public class DiscountDayOverride : IAutoMappingOverride<DiscountDay>
{
public void Override(AutoMapping<DiscountDay> mapping)
{
mapping.HasManyToMany( x => x.DiscountGroups )
.AsSet()
.Cascade
.SaveUpdate();
mapping.Cache.ReadWrite();
}
}
public class DiscountGroupOverride : IAutoMappingOverride<DiscountGroup>
{
public void Override(AutoMapping<DiscountGroup> mapping)
{
mapping.HasManyToMany( x => x.DiscountDay )
.AsBag()
.Inverse();
mapping.Cache.ReadWrite();
}
}
Well, I'm a complete and utter numpty. The empty set on DiscountGroups on the DiscountDay entity was causing the issue. For some reason I'd glossed over it and just didn't think that an empty set would do anything.
Updated code:
public virtual IEnumerable<DiscountGroup> DiscountGroups
{
get { return _discountGroups; }
}
Related
How use Bounded Context Pattern in AspnetBoilerplate, Is there any way to use to use Bounded Context Pattern in AspnetBoilerplate?
Connect with multiple database in ASP.NET ZERO/ASP.NET BOILERPLATE.
Note - Use seperate DB Context to use multiple Databases.
Step 1. Create modal class in "MultipleDbContextEfCoreDemo.Core" Project for your tables.
[Table ("tblStudent")] //Is in First Database
public class Student : Entity<long> {
public int ID { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
protected Student () { }
}
[Table ("tblCourses")] //Is in Second Database
public class Courses : Entity<long> {
public int ID { get; set; }
public string CourseName { get; set; }
public string Standard { get; set; }
protected Courses () { }
}
Step 2. In same project("MultipleDbContextEfCoreDemo.Core" Project) create/use "MultipleDbContextEfCoreDemoConsts.cs" file to add Database Connection names.
public class MultipleDbContextEfCoreDemoConsts
{
public const string LocalizationSourceName = "MultipleDbContextEfCoreDemo";
public const string ConnectionStringName = "Default";
public const string SecondDbConnectionStringName = "Second";
}
Step 3. In "MultipleDbContextEfCoreDemo.EntityFrameworkCore" Project goto "EntityFrameworkCore" Folder and create individual "DBContext" and "DbContextConfigurer" file for each database connection to which you want to connect.
FirstDatabase Setting -
required files to connect to first db -
1. FirstDbContext.cs
public class FirstDbContext : AbpDbContext, IAbpPersistedGrantDbContext {
/* Define an IDbSet for each entity of the application */
public DbSet<PersistedGrantEntity> PersistedGrants { get; set; }
public virtual DbSet<Student> Student { get; set; }
public FirstDbContext (DbContextOptions<FirstDbContext> options) : base (options) {
}
protected override void OnModelCreating (ModelBuilder modelBuilder) { }
}
2. FirstDbContextConfigurer
public static class FirstDbContextConfigurer {
public static void Configure (DbContextOptionsBuilder<FirstDbContext> builder, string connectionString) {
builder.UseSqlServer (connectionString);
}
public static void Configure (DbContextOptionsBuilder<FirstDbContext> builder, DbConnection connection) {
builder.UseSqlServer (connection);
}
}
SecondDatabase Setting -
required files to connect to second db -
1. SecondDbContext.cs
public class SecondDbContext : AbpDbContext, IAbpPersistedGrantDbContext {
/* Define an IDbSet for each entity of the application */
public DbSet<PersistedGrantEntity> PersistedGrants { get; set; }
public virtual DbSet<Student> Student { get; set; }
public SecondDbContext (DbContextOptions<SecondDbContext> options) : base (options) {
}
protected override void OnModelCreating (ModelBuilder modelBuilder) { }
}
2. SecondDbContextConfigurer
public static class SecondDbContextConfigurer {
public static void Configure (DbContextOptionsBuilder<SecondDbContext> builder, string connectionString) {
builder.UseSqlServer (connectionString);
}
public static void Configure (DbContextOptionsBuilder<SecondDbContext> builder, DbConnection connection) {
builder.UseSqlServer (connection);
}
}
Step 4. Then in same project("MultipleDbContextEfCoreDemo.EntityFrameworkCore") add "MyConnectionStringResolver.cs"
public class MyConnectionStringResolver : DefaultConnectionStringResolver
{
public MyConnectionStringResolver(IAbpStartupConfiguration configuration)
: base(configuration)
{
}
public override string GetNameOrConnectionString(ConnectionStringResolveArgs args)
{
if (args["DbContextConcreteType"] as Type == typeof(SecondDbContext))
{
var configuration = AppConfigurations.Get(WebContentDirectoryFinder.CalculateContentRootFolder());
return configuration.GetConnectionString(MultipleDbContextEfCoreDemoConsts.SecondDbConnectionStringName);
}
return base.GetNameOrConnectionString(args);
}
}
Step 5. Then in same project("MultipleDbContextEfCoreDemo.EntityFrameworkCore"), Update "MultipleDbContextEfCoreDemoEntityFrameworkCoreModule.cs" file to replace the "IConnectionStringResolver" with our custom implementation MyConnectionStringResolver.
[DependsOn(typeof(MultipleDbContextEfCoreDemoCoreModule), typeof(AbpEntityFrameworkCoreModule))]
public class MultipleDbContextEfCoreDemoEntityFrameworkCoreModule : AbpModule
{
public override void PreInitialize()
{
Configuration.ReplaceService<IConnectionStringResolver, MyConnectionStringResolver>();
// Configure first DbContext
Configuration.Modules.AbpEfCore().AddDbContext<FirstDbContext>(options =>
{
if (options.ExistingConnection != null)
{
FirstDbContextConfigurer.Configure(options.DbContextOptions, options.ExistingConnection);
}
else
{
FirstDbContextConfigurer.Configure(options.DbContextOptions, options.ConnectionString);
}
});
// Configure second DbContext
Configuration.Modules.AbpEfCore().AddDbContext<SecondDbContext>(options =>
{
if (options.ExistingConnection != null)
{
SecondDbContextConfigurer.Configure(options.DbContextOptions, options.ExistingConnection);
}
else
{
SecondDbContextConfigurer.Configure(options.DbContextOptions, options.ConnectionString);
}
});
}
public override void Initialize()
{
IocManager.RegisterAssemblyByConvention(typeof(MultipleDbContextEfCoreDemoEntityFrameworkCoreModule).GetAssembly());
}
}
Step 6. Create the Service in "MultipleDbContextEfCoreDemo.Application" project with Dto, Interface and Service Class.
ITestAppService.cs-
public interface ITestAppService : IApplicationService
{
List<string> GetStudentAndCourses();
}
TestAppService.cs
public class TestAppService : MultipleDbContextEfCoreDemoAppServiceBase, ITestAppService
{
private readonly IRepository<Student> _studentRepository; //in the first db
private readonly IRepository<Courses> _coursesRepository; //in the second db
public TestAppService(
IRepository<Student> studentRepository,
IRepository<Courses> coursesRepository
)
{
_studentRepository = studentRepository;
_coursesRepository = coursesRepository;
}
//a sample method uses both databases concurrently
public List<string> GetStudentAndCourses()
{
List<string> names = new List<string>();
var studentNames = _studentRepository.GetAllList().Select(p => "Student: " + p.FirstName).ToList();
names.AddRange(peopleNames);
var courseNames = _coursesRepository.GetAllList().Select(p => "Course: " + p.CourseName).ToList();
names.AddRange(courseNames);
return names;
}
}
Step 7. Add Database connectionStrings to your MultipleDbContextEfCoreDemo.Web/MultipleDbContextEfCoreDemo.Web.Host project's
"appsettings.json" file.
{
"ConnectionStrings": {
"Default":
"Server=XXX.XXX.XX.XX;Database=firstDB;Integrated Security=False;TrustServerCertificate=True;User ID=XX;Password=XXX;",
"Second":
"Server=XXX.XXX.XX.XX;Database=secondDB;Integrated Security=False;TrustServerCertificate=True;User ID=XX;Password=XXX;"
}
}
Step 8. Use Service in your angular/MVC project.
With EF you need one complete dbcontext for migrations.
Create other "bounded" dbcontext, with the entities to be ignored in modelbuilder, then use this in appservice.
Very simple answer
HTH
I am a newbie to with unity and unit of work pattern and I am trying to write a code, which connects to my webservice and does all the work.
Everything goes well until I use the Database but I get lost when I try to use the webservice.
I have wasted my 2 precious days, searching every single possible article related to it and applying it to my code, but no luck till date.
I know, by writing connection string to web.config and calling it in dbcontext class controller will connect to the required database, but I am not connecting to any database, so what changes I need to do in web/app.config. Also, even if I write my connection logic in dbcontext constructor, it still searches and fills the dbcontext with sql server details. I presume thats happening because I am using DBSet.
Guys, you are requested to have a look at my code, I have done and show me some hope that I can do it. Let me know, if you want any other info related to the code that you want to see.
thanks
DBCONTEXT
public class CVSContext : DbContext
{
public DbSet<CVSViewModel> CVS { get; set; }
public DbSet<Contact> Contacts { get; set; }
public DbSet<Account> Accounts { get; set; }
public CVSContext()
{
//CRM Start
var clientCredentials = new System.ServiceModel.Description.ClientCredentials();
clientCredentials.UserName.UserName = "";
clientCredentials.UserName.Password = "";
var serviceProxy = new Microsoft.Xrm.Sdk.Client.OrganizationServiceProxy(new Uri("http://Organization.svc"), null, clientCredentials, null);
serviceProxy.ServiceConfiguration.CurrentServiceEndpoint.Behaviors.Add(new ProxyTypesBehavior());
HttpContext.Current.Session.Add("ServiceProxy", serviceProxy);
//CRM End
}
}
GENERIC REPOSITORY
public class GenericRepository<TEntity> where TEntity : class
{
internal CVSContext context;
internal DbSet<TEntity> dbSet;
public GenericRepository(CVSContext context)
{
this.context = context;
this.dbSet = context.Set<TEntity>();
}
}
UNIT OF WORK
public interface IUnitOfWork : IDisposable
{
int SaveChanges();
}
public interface IDALContext : IUnitOfWork
{
ICVSRepository CVS { get; set; }
IContactRepository Contacts { get; set; }
//IAccountRepository Accounts { get; set; }
}
public class DALContext : IDALContext
{
private CVSContext dbContext;
private ICVSRepository cvs;
private IContactRepository contacts;
// private IAccountRepository accounts;
public DALContext()
{
dbContext = new CVSContext();
}
public ICVSRepository CVS
{
get
{
if (cvs == null)
cvs = new CVSRepository(dbContext);
return cvs;
}
set
{
if (cvs == value)
cvs = value;
}
}
public IContactRepository Contacts
{
get
{
if (contacts == null)
contacts = new ContactRepository(dbContext);
return contacts;
}
set
{
if (contacts == value)
contacts = value;
}
}
public int SaveChanges()
{
return this.SaveChanges();
}
public void Dispose()
{
if(contacts != null)
contacts.Dispose();
//if(accounts != null)
// accounts.Dispose();
if(dbContext != null)
dbContext.Dispose();
GC.SuppressFinalize(this);
}
}
SERVICE
public interface ICVSService
{
Contact CreateContact(Guid contactName, string productName, int price);
List<CVSViewModel> GetCVS();
List<Contact> GetContacts();
List<Account> GetAccounts();
}
public class CVSService : ICVSService, IDisposable
{
private IDALContext context;
public CVSService(IDALContext dal)
{
context = dal;
}
public List<CVSViewModel> GetCVS()
{
return context.CVS.All().ToList();
}
public List<Contact> GetContacts()
{
return context.Contacts.All().ToList();
}
public List<Account> GetAccounts()
{
return context.Accounts.All().ToList();
}
public Contact CreateContact(Guid contactName, string accountName, int price)
{
var contact = new Contact() { ContactId = contactName };
var account = new Account() { ContactName = accountName, Rent = price, Contact = contact };
//context.Contacts.Create(contact);
context.SaveChanges();
return contact;
}
public void Dispose()
{
if (context != null)
context.Dispose();
}
}
CONTROLLER
public ActionResult Index()
{
ViewData.Model = service.GetContacts();
return View();
}
It's all about proper abstractions. The common abstraction that is used between some data source (could be a db or ws) is the Repository pattern, or at a higher level the Unit of Work pattern. In fact Entity Framework DbContext is an implementation of the Unit of Work pattern, but it is tailored for databases. You can't use to communicate with a web service.
In that case you will have to write your own IRepository<T> abstraction and have a database specific implementation that uses a DbContext under the covers and a web service specific implementation that wraps a web service client proxy under the covers.
However, when your application gets more complex, you often find yourself wanting to have some sort of transaction like behavior. This is what the Unit of Work pattern if for: it presents a business transaction. Using the unit of work pattern to wrap multiple WS calls however, will get painful very soon. It's a lot of work to get right and in that case you will be much better of using a message based architecture.
With a message based architecture you define a single atomic operation (a business transaction or use case) as a specific message, for instance:
public class MoveCustomerCommand
{
public int CustomerId { get; set; }
public Address NewAddress { get; set; }
}
This is just an object (DTO) with a set of properties, but without behavior. Nice about this is that you can pass these kinds of objects over the wire using WCF or any other technology or process them locally without the need for the consumer to know.
Take a look at this article that describes it in detail. This article builds on top of that model and describes how you can write highly maintainable WCF services using this model.
Please can someone help me because I am getting confused.
I have an Entity like this:
public class Code
{
public int ID { get; set; }
public int UserID { get; set; }
public string CodeText { get; set; }
}
and an Interface like this:
public interface ICodeRepository
{
IQueryable<Code> Codes { get; }
void AddCode(Code code);
void RemoveCode(Code code);
Code GetCodeById(int id);
}
and a Repository like this:
public class SQLCodeRepository : ICodeRepository
{
private EFSQLContext context;
public SQLCodeRepository()
{
context = new EFSQLContext();
}
public IQueryable<Code> Codes
{
get { return context.Codes; }
}
public void AddCode(Code code)
{
context.Codes.Add(code);
context.SaveChanges();
}
public void RemoveCode(Code code)
{
context.Codes.Remove(code);
context.SaveChanges();
}
public Code GetCodeById(int id)
{
return context.Codes.Where(x => x.ID == id).FirstOrDefault();
}
}
and a Context like this:
public class EFSQLContext : DbContext
{
public DbSet<User> Users { get; set; }
public DbSet<Code> Codes { get; set; }
public DbSet<PortfolioUser> PortfolioUsers { get; set; }
}
If I declare my controller like this:
public class SearchController : Controller
{
private ICodeRepository cRepo;
public SearchController(ICodeRepository codeRepository)
{
cRepo = codeRepository;
}
}
and then try to do cRepo.GetCodeById(1) nothing happens. But if I declare private ICodeRepository rep = new SQLCodeRepository and then call rep.GetCodeById(1) I can see the method in the Repository being called.
What am I doing wrong?
It looks like from the constructor signature, you are going to be doing some dependency injection. The step you are missing is to set up a DI container using a tool like Castle Windsor. You then configure the MVC resolver to use the DI container to give you the correct implementation of ICodeRepository.
See this
You'll need to create a resolver that implements IDependencyResolver and IDependencyScope and a controller factory that inheritsDefaultControllerFactory
Once you have those you can do something like the following:
MyContainer container; // this needs to be a class level member of the asax
var configuration = GlobalConfiguration.Configuration;
container = new MyContainer() // may need additional stuff here depending on DI tool used
configuration.DependencyResolver = new MyDependancyResolver(container);
var mvcControllerFactory = new MyFactory(container.Kernel);
ControllerBuilder.Current.SetControllerFactory(mvcControllerFactory);
You would call the above code from the asax Application_Start()
See this answer for more specifics on using Ninject and MVC3
I want to use the same list of object in different models. The MainModel should take care about the content of the list so the SubModels using that list get the change as well.
Given following Model 'Customer'...
public class Customer
{
public Customer(List<Customer> customerList)
{
this.CustomerList= customerList;
this.CustomerAge= new CustomerAge(this.CustomerList);
}
public List<Customer> CustomerList
{
get;
set;
}
public AgeCustomer AgeCustomer
{
get;
set;
}
public void SetCustomerList(List<Customer> customerList)
{
this.CustomerList= customerList;
}
}
And the Model CustomerAge:
public class CustomerAge
{
List<Customer> customerListComplete;
public CustomerAge(List<Customer> customerList)
{
this.customerListComplete= customerList;
}
public List<Customer> CustomerListAgeOver40
{
get
{
return this.customerListComplete.Where(c => c.age > 40).ToList();
}
}
public List<Customer> CustomerListAgeUnder40
{
get
{
return this.customerListComplete.Where(c => c.age < 40).ToList();
}
}
public List<Customer> CustomerListAgeEquals40
{
get
{
return this.customerListComplete.Where(c => c.age = 40).ToList();
}
}
}
Pretty simple so far, I have a main model called Customer and a helper model called CustomerAge. When I change the CustomerList in Customer by calling Customer.SetCustomerList(newCustomerList), I thought that the CustomerListComplete in CustomerAge would change as well, but it dosen't. Why? How can I use the same list in both of models?
This is because your collection is referenced by, well, references.
CustomerList in Customer and customerListComplete in CustomerAge are just 'pointers' to a collection. When you changes CustomerList, customerListComplete doesn't change.
You need to add public void SetCustomerList(List<Customer> customerList) to CustomerAge and call it from Customer.SetCustomerList.
Other solution is to change CustomerAge constructor to get the instance of Customer and then use Customer.CustomerList:
public Customer(List<Customer> customerList)
{
this.CustomerList= customerList;
this.CustomerAge= new CustomerAge(this);
}
I am fairly new to MVC, but after playing with it (MVC 3/Razor), I am hooked.
I have a few questions:
1) What is the best, or most widely used pattern to develop MVC apps in? Repository, DDD, UOW?
2) I am using the Entity Framework 4, so could some please explain to me or point me to a good source that will explain the Repository Pattern w/EF4? Doesn't EF4 take place as the business layer and the data access layer? Does the Repository Pattern even provide a benefit?
3) Also, one last question, could someone explain the whole relationship between the Controller, the Model and the View? I get the basics, but maybe a little more in depth of the correct way to use it. View Models - Say I have a view that displays customer info, and one that edits it, should I have a view model and an edit model, or can the be passed around?
4) Examples??
Thanks for the help up front,
$("Sam")
** EDIT **
Am I on the right track here:
Public Class HomeController
Inherits System.Web.Mvc.Controller
Function Index(ByVal id As Integer) As ActionResult
Return View(New HomeModel)
End Function
<HttpPost()> _
Function Index(ByVal Model As HomeModel) As ActionResult
Return View(Model)
End Function
End Class
Public Class HomeModel
Private _Repository As IRepository(Of Customer)
Public Property Customer As Customer
Public Sub New()
End Sub
Public Sub New(ByVal ID As Integer)
_Repository = New CustomerRepository
Customer = _Repository.GetByID(ID)
End Sub
End Class
Public Interface IRepository(Of T)
Function GetByID(ByVal ID As Integer) As T
Sub Add(ByVal Entity As T)
Sub Delete(ByVal Entity As T)
End Interface
Public Class CustomerRepository
Implements IRepository(Of Customer)
Public Sub Add(ByVal Entity As Customer) Implements IRepository(Of Customer).Add
End Sub
Public Sub Delete(ByVal Entity As Customer) Implements IRepository(Of Customer).Delete
End Sub
Public Function GetByID(ByVal ID As Integer) As Customer Implements IRepository(Of Customer).GetByID
Return New Customer With {.ID = ID, .FirstName = "Sam", .LastName = "Striano"}
End Function
End Class
Public Class Customer
Public Property ID As Integer
Public Property FirstName As String
Public Property LastName As String
End Class
I use generic repositories that get instantiated in a service class (using Dependency Injection with Ninject).
The service class essentially performs two functions:
It provides all the methods that the controller will consume.
It has a property called ViewModel, that essentially maps the data that the views need into a MyViewModel class.
The Controller consumes the service class. With this "pattern", your controllers look like:
namespace ES.eLearningFE.Areas.Courses.Controllers
{
public partial class CourseController : Controller
{
ICourseDisplayService service;
public CourseController(ICourseDisplayService service)
{
this.service = service;
}
public virtual ActionResult Display(int CourseId, int StepOrder, string PupilName, string TutorName)
{
service.CourseId = CourseId;
service.StepOrder = StepOrder;
service.PupilName = PupilName;
service.TutorName = TutorName;
if (Request.IsAjaxRequest())
{
return PartialView(service.ViewModel);
}
else
{
return View(service.ViewModel);
}
}
}
}
The ViewModel class only hold display data and no methods (except the odd really simple method to retrieve data from another property that is, for example a List<> object).
Works really well. An example of a service class:
namespace ES.eLearning.Domain.Services.Courses
{
public class SqlCourseDisplayService : ICourseDisplayService
{
DataContext db;
public SqlCourseDisplayService(DbDataContextFactory contextFactory)
{
db = contextFactory.Make();
CoursesRepository = new SqlRepository<Course>(db);
StepsRepository = new SqlRepository<CourseStep>(db);
StepLinksRepository = new SqlRepository<StepLink>(db);
UserCoursesRepository = new SqlRepository<UserCourse>(db);
CourseTutorsRepository = new SqlRepository<CourseTutor>(db);
UsersRepository = new SqlRepository<User>(db);
}
#region ICourseDisplayService Members
public ViewModels.CourseDisplayVM ViewModel
{
get
{
return new ViewModels.CourseDisplayVM
{
CourseId = this.CourseId,
CourseName = this.Course.Name,
Steps = this.Steps,
ActiveStepIndex = this.ActiveStepIndex,
CurrentStepIndex = this.CurrentStepIndex,
Pupil = new UserDto { UserId = this.PupilId, UserName = this.PupilName },
Tutors = this.GetTutors(this.CourseId),
Tutor = tutorName == null ? null : new UserDto { UserName = this.TutorName, UserId = this.TutorId}
};
}
}
#region Entities
int courseId;
public int CourseId
{
get
{
if (courseId == 0) throw new ApplicationException("Invalid Course Id!");
return courseId;
}
set
{
if (value == 0) throw new ApplicationException("Invalid Course Id!");
try
{
Course = (from c in CoursesRepository.Query where c.CourseId == value select c).First();
Steps = Course.CourseSteps.ToList();
courseId = value;
}
catch {throw new ApplicationException("No Course found for Course Id: " + value);}
}
}
public Data.Course Course { get; private set; }
public int StepOrder { get; set; }
public List<Data.CourseStep> Steps { get; private set; }
public int ActiveStepIndex
{
get
{
if (PupilName == null)
{
throw new ApplicationException("Pupil not set!");
}
if (CourseId == 0)
{
throw new ApplicationException("Course not set!");
}
try
{
var x = (from uc in UserCoursesRepository.Query where (uc.IdCourse == CourseId) && (uc.UserName == PupilName) select uc).First();
return x.ActiveStepIndex;
}
catch { throw new ApplicationException("Could not get Active Step!"); }
}
}
#endregion
#region Users
string tutorName;
public string TutorName
{
get
{
if (tutorName == null) throw new ApplicationException("Invalid call to get Tutor Name [Null Tutor Name]!");
return tutorName;
}
set
{
tutorName = value;
TutorId = (Guid)Membership.GetUser(tutorName).ProviderUserKey;
}
}
public Guid TutorId { get; set; }
string pupilName;
public string PupilName
{
get { return pupilName; }
set
{
pupilName = value;
PupilId = (Guid)Membership.GetUser(pupilName).ProviderUserKey;
}
}
public Guid PupilId { get; set; }
#endregion
#region Utility Properties
public int CurrentStepIndex { get; set; }
public int StepCount
{
get
{
return Steps == null ? 0 : Steps.Count();
}
}
#endregion
#region Private Utilities
private List<UserDto> GetTutors(int CourseId)
{
return (from ct in CourseTutorsRepository.Query join u in UsersRepository.Query
on ct.TutorName equals u.UserName
where (ct.CourseId == courseId)
select new UserDto { UserName = ct.TutorName, UserId = u.UserId }).ToList();
}
#endregion
#region Repositories
private IRepository<Course> CoursesRepository
{
get;
set;
}
private IRepository<CourseStep> StepsRepository
{
get;
set;
}
private IRepository<StepLink> StepLinksRepository
{
get;
set;
}
private IRepository<UserCourse> UserCoursesRepository
{
get;
set;
}
private IRepository<CourseTutor> CourseTutorsRepository
{
get;
set;
}
private IRepository<User> UsersRepository
{
get;
set;
}
#endregion
#endregion
}
}
May not be everyone's choice, but hey, it works for me... AND (more importantly) my clients and their users.
Edit
As requested in the comment below, the Repository that I use:
namespace ES.eLearning.Domain
{
public class SqlRepository<T> : IRepository<T> where T : class
{
DataContext db;
public SqlRepository(DataContext db)
{
this.db = db;
}
#region IRepository<T> Members
public IQueryable<T> Query
{
get { return db.GetTable<T>(); }
}
public List<T> FetchAll()
{
return Query.ToList();
}
public void Add(T entity)
{
db.GetTable<T>().InsertOnSubmit(entity);
}
public void Delete(T entity)
{
db.GetTable<T>().DeleteOnSubmit(entity);
}
public void Attach(T entity)
{
db.GetTable<T>().Attach(entity);
}
public void Save()
{
db.SubmitChanges();
}
#endregion
}
}
And the IRepository Interface:
namespace Wingspan.Web.Mvc
{
public interface IRepository<TEntity> where TEntity : class
{
List<TEntity> FetchAll();
IQueryable<TEntity> Query {get;}
void Add(TEntity entity);
void Delete(TEntity entity);
void Attach(TEntity entity);
void Save();
}
}
This should help you getting started. There are a lot of tutorials and videos available; for example:
Understanding Models, Views and Controllers
The ASP.NET MVC 2.0 basics and excellent introduction by Scott Hanselman. Personally one of my favorite speakers.
And also at www.asp.net; there are a few tutorials/examples to help you getting started. For example the Music Store sample
Unfortunately, I'm not so familiar with EF4/Repository pattern. But here's a blogpost about this pattern.
1) I would say that the repository pattern is the most widely used, then there is inversion of controll too.
2) I can't really point out the benefits with using a repository for entity framework other than that the controller should not know about how to acces data other then asking a repository. This makes it easy to switch it out sometime.
You can also eager load the data to make sure that the view don't call the database in every iteration of a foreach, for example a collection of users to display data from a child entity. You can probly do this anyway, but I feel that the repository is the right place to do it.
3) I can't tell you about the concept in a more in depth way, but I can tell some about viewmodels. In my opinion you should only use viewmodels if there is anything more then one entity you want to send to the view, for example a list of countries. You can alo use a viewmodel to "flatten" out very complex objects.
I would defiantly say the repository pattern is used a lot. This pattern can be used with Dependency Injection. Using Dependency Injection makes Unit Testing a breeze because you can snap different repositories to an abstract repoistory. Check out http://ninject.org/ for a simple to use Dependecy injector for .NET.
View Models should hold display data and transfer that data from the controller to the view. If you want to edit and display customer info, take a look at this