Cannot convert type System.Data.Entity.DbSet to System.Collections.Generic.ICollection - asp.net-mvc-3

I am using Entity Framework 4.1 code first in an MVC 3 app.
I have the following repository:
public class BankRepository : IBankRepository
{
HefContext db = new HefContext();
public ICollection<Bank> GetAll()
{
return db.Banks;
}
}
I get an error when returning db.Banks. I'm not sure what it means, can someone please help clarify and how to change it so that the error goes away? The error is:
Cannot implicitly convert type 'System.Data.Entity.DbSet<MyProject.Core.DomainObjects.Bank>' to 'System.Collections.Generic.ICollection<MyProject.Core.DomainObjects.Bank>'. An explicit conversion exists (are you missing a cast?)
What is returned by db.Banks? An IEnumerable?

db.Banks is of type DbSet. This class does not implement ICollection interface. Change the return type of the method to IQueryable<Bank> or IEnumerable<Bank>.
public class BankRepository : IBankRepository
{
HefContext db = new HefContext();
public IQueryable<Bank> GetAll()
{
return db.Banks;
}
}

ICollection is used only as the backing property to support LazyLoading, not as the result of a method. Check here ;)

Related

AspnetBoilerplate modular: The entity type XXX is not part of the model for the current context

Sorry for my bad English, Could anyone help me with this error as below:
I have followed this tutorial to create a new module application (named Payment) on AspnetZero framework (named FastOne).
In the second DbContext, I change the default conn to my second database and add new entity name BankCode. After add-migration and update-database, everything works well. New database was created with 1 table name BankCode
I went to create a AppService in .Application module project as below:
public class BankCodeAppService : FastOneAppServiceBase, IBankCodeAppService
{
//from PaymentDbContext
private readonly IRepository<BankCode> _repository;
public BankCodeAppService(IRepository<BankCode> repository)
{
_repository = repository;
}
public ListResultDto<BankCodeDto> GetAllBankCodeDto()
{
try
{
var result = _repository.GetAll().ToList();
return new ListResultDto<BankCodeDto>(result.MapTo<List<BankCodeDto>>());
}
catch (Exception ex)
{
throw new NotImplementedException();
}
}
}
This is my PaymentDbContext
[DefaultDbContext]
[AutoRepositoryTypes(
typeof(IPaymentRepositoryBase<>),
typeof(IPaymentRepositoryBase<,>),
typeof(PaymentRepositoryBase<>),
typeof(PaymentRepositoryBase<,>)
)]
public class PaymentDbContext : FastOneDbContext
{
/* Define an IDbSet for each entity of the application */
public virtual IDbSet<BankCode.BankCode> BankCodes { get; set; }
//TODO: Define an IDbSet for your Entities...
public PaymentDbContext() : base("SecondConn") { }
public PaymentDbContext(string nameOrConnectionString) : base(nameOrConnectionString) { }
public PaymentDbContext(DbConnection connection) : base(connection) { }
}
The api was created successfully, but when I called to it, it returned the error as below:
The entity type BankCode is not part of the model for the current
context.
I tried to debug and realize that the repository is FastOneDbContext instead of PaymentDbContext : [Wrong repository when debugging][2]
I'm totally new with AspNetBoilerplate and module Zero. So could anyone please to help me. Thank
Update: This is my PaymentRepositoryBase
namespace FastOne.EntityFramework.Repositories
{
public class PaymentRepositoryBase<TEntity, TPrimaryKey> : FastOneRepositoryBase<TEntity, TPrimaryKey>
where TEntity : class, IEntity<TPrimaryKey>
{
public PaymentRepositoryBase(IDbContextProvider<PaymentDbContext> dbContextProvider) : base(dbContextProvider) { }
//do not add any method here, add to the class above (since this inherits it)
}
public abstract class PaymentRepositoryBase<TEntity> : PaymentRepositoryBase<TEntity, int>
where TEntity : class, IEntity<int>
{
public PaymentRepositoryBase(IDbContextProvider<PaymentDbContext> dbContextProvider) : base(dbContextProvider) { }
//do not add any method here, add to the class above (since this inherits it)
}
}
Update 3
Thank for your help Aaron, everything goes correctly, this is the newest error, I have searched some solutions but they didn't work. Please help
No component for supporting the service
FastOne.EntityFramework.PaymentDbContext was found
Update 4
I tried to add this method to PaymentDataModule:
public override void Initialize()
{
IocManager.RegisterAssemblyByConvention(Assembly.GetExecutingAssembly());
}
It worked!, I can see _repository get correct context. but when i run, it raised this error:
System.Data.SqlClient.SqlException: Invalid object name
'dbo.BankCode'.
I realized that the connection was wrong. It was the connstring of the first context
Update 5: I found that I have 3 constructors in PaymentDbContext. So i removed these lines:
public PaymentDbContext() : base("LocalPaymentConn") { }
//public PaymentDbContext(string nameOrConnectionString) : base(nameOrConnectionString) { }
//public PaymentDbContext(DbConnection connection) : base(connection) { }
-->It received the correct connection string. So awesome!! Thanks Aaron and Tien for all your help. Thank you
You should inject IPaymentRepositoryBase as you have specified in AutoRepositoryTypes.
public class BankCodeAppService : FastOneAppServiceBase, IBankCodeAppService
{
private readonly IPaymentRepositoryBase<BankCode> _repository;
public BankCodeAppService(IPaymentRepositoryBase<BankCode> repository)
{
_repository = repository;
}
}
Update 1
ComponentActivator: could not instantiate FastOne.EntityFramework.Repositories.PaymentRepositoryBase`1‌​[[FastOne.BankCode.B‌​ankCode, FastOne.Payment.Core, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]
Remove abstract keyword from the class declaration for PaymentRepositoryBase<TEntity>.
Update 2
Target does not implement interface FastOne.Domain.Repositories.IPaymentRepositoryBase`1[[FastOn‌​e.BankCode.BankCode, FastOne.Payment.Core, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]\r\nParameter name: target
Make PaymentRepositoryBase implement IPaymentRepositoryBase.
public class PaymentRepositoryBase<TEntity> : PaymentRepositoryBase<TEntity, int>, IPaymentRepositoryBase<TEntity>
where TEntity : class, IEntity<int>
{
public PaymentRepositoryBase(IDbContextProvider<PaymentDbContext> dbContextProvider) : base(dbContextProvider) { }
}
You are using mutilple dbcontext in the app. So the second context must be inherit from AbpDbContext to ABP inject this correctly. See MultipleDbContextDemo example on https://github.com/aspnetboilerplate/aspnetboilerplate-samples.
Hope this will help you.

Spring form ModelAttribute List binding

There are way to bind List object by using spring modelAttribute?
Actually, I know that it can be done by using Wrapper class having list member variable.
like this
Dto :
public class SampleDto {
private List<SubSampleDto> sampleList;
}
Controller :
#RequestMapping(value = "/sample/insert.ajax")
public String set(#ModelAttribute("sampleDto") SampleDto dto) {
...
}
But, I want to know the way not to use wrapper class.
Thanks
You could bind it like,
#ModelAttribute("sampleList")
public List<SubSampleDto> getAll() {
return subSampleDtoService.getAll(); //or something to get SubSampleDto list
}
if i understood you correctly

Convert IQueryable<T> to IQueryable<Y>

I'm try to do this : I'm using EF code first to map an old existing database. There's many fields with the wrong type (ex: char(1) used as boolean) so I've created a wrapper class for my db context that maps perfectly to the database table. Now, I want to expose an IQueryable of my Entity type on my repository. See my example :
public class MyContext:DbContext
{
public DbSet<WrappedEntity> WrapperEntities;
}
public class Repository
{
private MyContext _context;
//contructors omitted
public IQueryable<Entity> GetEntities()
{
return _context.WrapperEntities; //doesn't compile, I need some convertion here
}
}
I already have my convertion routine, the only thing missing is a way to query my DbContext thought my repository without exposing the WrappedEntity class, Is it possible and how ?
Thanks.
Usually you project with Queryable.Select to change the type of your query...
public IQueryable<Entity> GetEntities()
{
return _context.WrapperEntities.Select(x => new Entity(){...});
}

Why cannot type arguments be inferred from this simple code?

Using .NET 3.5, but the Select call gives the error. Shouldn't the compiler be clever enough to infer this? If not, why not?
public IEnumerable<Customer> TableToCustomers(Table table)
{
return table.Rows.Select(RowToCustomer);
}
private Customer RowToCustomer(TableRow row)
{
return new Customer { ... };
}
The Rows property is defined as TableRowCollection Rows {get;}
public sealed class TableRowCollection : IList, ICollection, IEnumerable
It is not IEnumerable<TableRow>, so it is just IEnumerable, therefore it cannot infer the type as being TableRow.
You can do this instead:
public IEnumerable<Customer> TableToCustomers(Table table)
{
return table.Rows.Cast<TableRow>().Select(RowToCustomer);
}
table.Rows.OfType<DataRow>().Select(RowToCustomer);

Issues with my MVC repository pattern and StructureMap

I have a repository pattern i created on top of the ado.net entity framework. When i tried to implement StructureMap to decouple my objects, i kept getting StackOverflowException (infinite loop?). Here is what the pattern looks like:
IEntityRepository where TEntity : class
Defines basic CRUD members
MyEntityRepository : IEntityRepository
Implements CRUD members
IEntityService where TEntity : class
Defines CRUD members which return common types for each member.
MyEntityService : IEntityService
Uses the repository to retrieve data and return a common type as a result (IList, bool and etc)
The problem appears to be with my Service layer. More specifically with the constructors.
public PostService(IValidationDictionary validationDictionary)
: this(validationDictionary, new PostRepository())
{ }
public PostService(IValidationDictionary validationDictionary, IEntityRepository<Post> repository)
{
_validationDictionary = validationDictionary;
_repository = repository;
}
From the controller, i pass an object that implements IValidationDictionary. And i am explicitly calling the second constructor to initialize the repository.
This is what the controller constructors look like (the first one creates an instance of the validation object):
public PostController()
{
_service = new PostService(new ModelStateWrapper(this.ModelState));
}
public PostController(IEntityService<Post> service)
{
_service = service;
}
Everything works if i don't pass my IValidationDictionary object reference, in which case the first controller constructor would be removed and the service object would only have one constructor which accepts the repository interface as the parameter.
I appreciate any help with this :) Thanks.
It looks like the circular reference had to do with the fact that the service layer was dependent on the Controller's ModelState and the Controller dependent on the Service layer.
I had to rewrite my validation layer to get this to work. Here is what i did.
Define generic validator interface like below:
public interface IValidator<TEntity>
{
ValidationState Validate(TEntity entity);
}
We want to be able to return an instance of ValidationState which, obviously, defines the state of validation.
public class ValidationState
{
private readonly ValidationErrorCollection _errors;
public ValidationErrorCollection Errors
{
get
{
return _errors;
}
}
public bool IsValid
{
get
{
return Errors.Count == 0;
}
}
public ValidationState()
{
_errors = new ValidationErrorCollection();
}
}
Notice that we have an strongly typed error collection which we need to define as well. The collection is going to consist of ValidationError objects containing the property name of the entity we're validating and the error message associated with it. This just follows the standard ModelState interface.
public class ValidationErrorCollection : Collection<ValidationError>
{
public void Add(string property, string message)
{
Add(new ValidationError(property, message));
}
}
And here is what the ValidationError looks like:
public class ValidationError
{
private string _property;
private string _message;
public string Property
{
get
{
return _property;
}
private set
{
_property = value;
}
}
public string Message
{
get
{
return _message;
}
private set
{
_message = value;
}
}
public ValidationError(string property, string message)
{
Property = property;
Message = message;
}
}
The rest of this is StructureMap magic. We need to create validation service layer which will locate validation objects and validate our entity. I'd like to define an interface for this, since i want anyone using validation service to be completely unaware of the StructureMap presence. Besides, i think sprinkling ObjectFactory.GetInstance() anywhere besides the bootstrapper logic a bad idea. Keeping it centralized is a good way to insure good maintainability. Anyway, i use the decorator pattern here:
public interface IValidationService
{
ValidationState Validate<TEntity>(TEntity entity);
}
And we finally implement it:
public class ValidationService : IValidationService
{
#region IValidationService Members
public IValidator<TEntity> GetValidatorFor<TEntity>(TEntity entity)
{
return ObjectFactory.GetInstance<IValidator<TEntity>>();
}
public ValidationState Validate<TEntity>(TEntity entity)
{
IValidator<TEntity> validator = GetValidatorFor(entity);
if (validator == null)
{
throw new Exception("Cannot locate validator");
}
return validator.Validate(entity);
}
#endregion
}
I'm going to be using validation service in my controller. We could move it to the service layer and have StructureMap use property injection to inject an instance of controller's ModelState to the service layer, but i don't want the service layer to be coupled with ModelState. What if we decide to use another validation technique? This is why i'd rather put it in the controller. Here is what my controller looks like:
public class PostController : Controller
{
private IEntityService<Post> _service = null;
private IValidationService _validationService = null;
public PostController(IEntityService<Post> service, IValidationService validationService)
{
_service = service;
_validationService = validationService;
}
}
Here i am injecting my service layer and validaton service instances using StructureMap. So, we need to register both in StructureMap registry:
ForRequestedType<IValidationService>()
.TheDefaultIsConcreteType<ValidationService>();
ForRequestedType<IValidator<Post>>()
.TheDefaultIsConcreteType<PostValidator>();
That's it. I don't show how i implement my PostValidator, but it's simply implementing IValidator interface and defining validation logic in the Validate() method. All that's left to do is call your validation service instance to retrieve the validator, call the validate method on your entity and write any errors to ModelState.
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Create([Bind(Exclude = "PostId")] Post post)
{
ValidationState vst = _validationService.Validate<Post>(post);
if (!vst.IsValid)
{
foreach (ValidationError error in vst.Errors)
{
this.ModelState.AddModelError(error.Property, error.Message);
}
return View(post);
}
...
}
Hope i helped somebody out with this :)
I used a similar solution involving a generic implementor of IValidationDictionary uses a StringDictionary and then copied the errors from this back into the model state in the controller.
Interface for validationdictionary
public interface IValidationDictionary
{
bool IsValid{get;}
void AddError(string Key, string errorMessage);
StringDictionary errors { get; }
}
Implementation of validation dictionary with no reference to model state or anything else so structuremap can create it easily
public class ValidationDictionary : IValidationDictionary
{
private StringDictionary _errors = new StringDictionary();
#region IValidationDictionary Members
public void AddError(string key, string errorMessage)
{
_errors.Add(key, errorMessage);
}
public bool IsValid
{
get { return (_errors.Count == 0); }
}
public StringDictionary errors
{
get { return _errors; }
}
#endregion
}
Code in the controller to copy the errors from the dictionary into the model state. This would probably be best as an extension function of Controller.
protected void copyValidationDictionaryToModelState()
{
// this copies the errors into viewstate
foreach (DictionaryEntry error in _service.validationdictionary.errors)
{
ModelState.AddModelError((string)error.Key, (string)error.Value);
}
}
thus bootstrapping code is like this
public static void BootstrapStructureMap()
{
// Initialize the static ObjectFactory container
ObjectFactory.Initialize(x =>
{
x.For<IContactRepository>().Use<EntityContactManagerRepository>();
x.For<IValidationDictionary>().Use<ValidationDictionary>();
x.For<IContactManagerService>().Use<ContactManagerService>();
});
}
and code to create controllers is like this
public class IocControllerFactory : DefaultControllerFactory
{
protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
{
return (Controller)ObjectFactory.GetInstance(controllerType);
}
}
Just a quick query on this. It's helped me out quite a lot so thanks for putting the answer up, but I wondered which namespace TEntity exists in? I see Colletion(TEntity) needs System.Collections.ObjectModel. My file compiles without anything further but I see your TEntity reference highlighted in Blue which suggests it has a class type, mine is Black in Visual Studio. Hope you can help. I'm pretty keen to get this working.
Have you found any way to seperate validation into the service layer at all? My gut tells me that validating in the Controller is a bit smelly but I've looked high and low to find a way to pass validation error messages back to the controller without tightly coupling the service layer to the controller and can't find anything. :(
Again, thanks for the great post!
Lloyd

Resources