Unmapped properties: _entityWrapper - entity-framework-6

Unmapped members were found. Review the types and members below.
Add a custom mapping expression, ignore, add a custom resolver, or modify the source/destination type
For no matching constructor, add a no-arg ctor, add optional arguments, or map all of the constructor parameters
AutoMapper created this type map for you, but your types cannot be mapped using the current configuration.
CustomerDto -> Customer_F18BD0407D7AB3084DFC14364CBC838E797CB114E45768DA5EB22B4A1CC94C26 (Destination member list)
WebApiCollection.DTO.CustomerDto -> System.Data.Entity.DynamicProxies.Customer_F18BD0407D7AB3084DFC14364CBC838E797CB114E45768DA5EB22B4A1CC94C26 (Destination member list)
Unmapped properties:
_entityWrapper
var customerInDb = _dbContext.Customers.SingleOrDefault(p => p.Id == customerDto.Id);
if (customerInDb == null)
return NotFound();
customerInDb = Mapper.Map(customerDto, customerInDb);

Have you tried?
customerInDb = Mapper.Map<Customer>(customerDto);

This can occur when the fields between the Dto and the Entity class don't line up. For example. My Dto contains two fields
public class ReworkDto: FullAuditEntity
{
public string WorkOrderNumber { get; set; }
public string WorkOrderBarcode { get; set; }
}
Those two fields are also in the entity class but the entity class also includes a navigation property (ReworkDetails)
[Table("Quality_Rework")]
public class QualityRework : FullAuditEntity
{
[Required, Column(Order = 8)]
public virtual string WorkOrderNumber { get; set; }
[Required, Column(Order = 9)]
public virtual string WorkOrderBarcode { get; set; }
public virtual ICollection<QualityReworkDetail> ReworkDetails { get; set; }
}
The particular error for this post would surface if I tried updating, using the following code
private void Update(ReworkDto entityDto)
{
try
{
var entityToUpdate = DbContext.QualityRework.FirstOrDefault(x => x.Id == entityDto.Id);
var updateRework = _autoMapper.Map(entityDto, entityToUpdate);
}
catch (Exception exc)
{
Console.WriteLine(exc);
throw;
}
}
To avoid getting the error I would need to CreateMap (AutoMapperModule.cs), instructing AutoMapper that when mapping between Dto -> Entity to Ignore() the ReworkDetails field.
CreateMap<domain.DTO.Quality.ReworkDto, infrastructure.Entities.Quality.QualityRework>()
.ForMember(dest => dest.ReworkDetails, opt => opt.Ignore());

Related

dot net core custom model binding for generic type parameters in mvc action methods

I am building a simple search, sort, page feature. I have attached the code below.
Below are the usecases:
My goal is to pass the "current filters" via each request to persist them particularly while sorting and paging.
Instead of polluting my action method with many (if not too many) parameters, I am thinking to use a generic type parameter that holds the current filters.
I need a custom model binder that can be able to achieve this.
Could someone please post an example implementation?
PS: I am also exploring alternatives as opposed to passing back and forth the complex objects. But i would need to take this route as a last resort and i could not find a good example of custom model binding generic type parameters. Any pointers to such examples can also help. Thanks!.
public async Task<IActionResult> Index(SearchSortPage<ProductSearchParamsVm> currentFilters, string sortField, int? page)
{
var currentSort = currentFilters.Sort;
// pass the current sort and sortField to determine the new sort & direction
currentFilters.Sort = SortUtility.DetermineSortAndDirection(sortField, currentSort);
currentFilters.Page = page ?? 1;
ViewData["CurrentFilters"] = currentFilters;
var bm = await ProductsProcessor.GetPaginatedAsync(currentFilters);
var vm = AutoMapper.Map<PaginatedResult<ProductBm>, PaginatedResult<ProductVm>>(bm);
return View(vm);
}
public class SearchSortPage<T> where T : class
{
public T Search { get; set; }
public Sort Sort { get; set; }
public Nullable<int> Page { get; set; }
}
public class Sort
{
public string Field { get; set; }
public string Direction { get; set; }
}
public class ProductSearchParamsVm
{
public string ProductTitle { get; set; }
public string ProductCategory { get; set; }
public Nullable<DateTime> DateSent { get; set; }
}
First create the Model Binder which should be implementing the interface IModelBinder
SearchSortPageModelBinder.cs
public class SearchSortPageModelBinder<T> : IModelBinder
{
public Task BindModelAsync(ModelBindingContext bindingContext)
{
if (bindingContext == null)
{
throw new ArgumentNullException(nameof(bindingContext));
}
SearchSortPage<T> ssp = new SearchSortPage<T>();
//TODO: Setup the SearchSortPage<T> model
bindingContext.Result = ModelBindingResult.Success(ssp);
return TaskCache.CompletedTask;
}
}
And then create the Model Binder Provider which should be implementing the interface IModelBinderProvider
SearchSortPageModelBinderProvider.cs
public class SearchSortPageModelBinderProvider : IModelBinderProvider
{
public IModelBinder GetBinder(ModelBinderProviderContext context)
{
if (context == null)
{
throw new ArgumentNullException(nameof(context));
}
if (context.Metadata.ModelType.GetTypeInfo().IsGenericType &&
context.Metadata.ModelType.GetGenericTypeDefinition() == typeof(SearchSortPage<>))
{
Type[] types = context.Metadata.ModelType.GetGenericArguments();
Type o = typeof(SearchSortPageModelBinder<>).MakeGenericType(types);
return (IModelBinder)Activator.CreateInstance(o);
}
return null;
}
}
And the last thing is register the Model Binder Provider, it should be done in your Startup.cs
public void ConfigureServices(IServiceCollection services)
{
.
.
services.AddMvc(options=>
{
options.ModelBinderProviders.Insert(0, new SearchSortPageModelBinderProvider());
});
.
.
}

Unable to cast the type 'System.Int32' to type 'System.Object'. LINQ to Entities

I am working on MVC and Entity Framework. I have written a function for multiple record delete.
The model is:
public partial class Category
{
public Category()
{
//this.Products = new HashSet<Product>();
}
public int CategoryID { get; set; }
public string CategoryName { get; set; }
public string Description { get; set; }
public byte[] Picture { get; set; }
public virtual ICollection<Product> Products { get; set; }
}
Controller is:
public ActionResult DeleteMultipleCategories(int[] id)
{
try
{
foreach (Category item in _db.Categories.Where(x => id.Equals(x.CategoryID)).ToList())
_db.Categories.Remove(item);
_db.SaveChanges();
return new HttpStatusCodeResult(HttpStatusCode.OK);
}
catch
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
It is giving an error like
"Unable to cast the type 'System.Int32' to type 'System.Object'. LINQ to Entities only supports casting EDM primitive or enumeration types.".
The statement "id.Equals(x.CategoryID)).ToList()" is responsible the error.
If I change it to id.Contains(x.CategoryID)).ToList(), it is working fine.
I don't want to use "Contains" as it will not give actual result e.g. if I want to delete the record no. 1 it will also delete record no. 11, 111 etc.
Any help will be thankfully accepted.
Partha
For the int datatype you have to use == as the comparator. So your linq statement should be something like .where(m =>m.id == x.CategoryID).ToList()

Unable to create a constant value of type 'T'. Only primitive types ('such as Int32, String, and Guid') are supported in this context

I see alot of question about this error, but some one can tell me why I get this error in my code?
I have the User and Group in my app, they have many to many relationship:
public class Group
{
[Key]
public int GId { get; set; }
public string GName { get; set; }
public virtual ICollection<UserProfile> Members { get; set; }
public Group()
{
Members = new HashSet<UserProfile>();
}
}
public class UserProfile
{
[Key]
public Guid UserId { get; set; }
[Required]
public string UserName { get; set; }
public virtual ICollection<Group> Groups { get; set; }
public UserProfile()
{
Groups = new HashSet<Group>();
}
}
I want to get all the Group that a User has Join ans pass it to a ViewBag, so:
UserProfile user = core.Profiles.Find(1);
//ok, no error in controller, but view...
ViewBag.JoinGroups = core.Groups.Where(g => g.Members.Contains(user));
But I get the error at View:
#if (ViewBag.JoinGroups != null)
{
foreach (var g in ViewBag.JoinGroups)//My issue start here
{
<p>#g.GId</p>
}
}
And it said:
Unable to create a constant value of type 'Project.Model.UserProfile'.
Only primitive types ('such as Int32, String, and Guid') are supported
in this context.
Do I missing any thing?
The message is clear: EF Linq queries do not support passing entities.
You can work around it by changing this piece:
UserProfile user = core.Profiles.Find(1);
ViewBag.JoinGroups = core.Groups.Where(g => g.Members.Contains(user));
For this:
ViewBag.JoinGroups = core.Groups.Where(g => g.Members.Select(x => x.UserId)
.Contains(1));
This is not specific to a ViewBag or anything. It's just the deferred execution pitfall: not until the foreach is the query executed. You would have seen the exception earlier by doing core.Groups.Where(g => g.Members.Contains(user)).ToList();.
By the way you pose it is clear that you already know that referencing non-scalar variables is not supported in entity framework, but allow me to mention it for the sake of completeness.

Complex Type Ignored by Entity Framework Code First

Building on Ladislav's answer to
Entity Framework Code First and Collections of Primitive Types
I'm attempting to create a wrapper type EfObservableCollection<T> around an ObservableCollection<T> that has an additional helper property to simplify persistence (certainly this solution has trade-offs, but it's seems workable for my domain).
However, properties of type EfObservableCollection<T> seem to be ignored by EF. No appropriate columns are created in the database. Guessing that implementing IEnumerable<T> might trigger EF to ignore that type, I commented out that implementation with no change in behavior.
What am I missing here?
Entity Class
public class A
{
[DataMember]
public long Id { get; set; }
[DataMember]
public string Text { get; set; }
// Tags is not persisted
[DataMember]
public EfObservableCollection<string> Tags { get; set; }
}
Wrapper Class
[ComplexType]
public class EfObservableCollection<T> : IEnumerable<T>
{
const string VALUE_SEPARATOR = "\x8"; // Backspace character. Unlikely to be actually entered by a user. Assumes ASCII or UTF-8.
readonly string[] VALUE_SEPARATORS = new string[] { VALUE_SEPARATOR };
[NotMapped]
protected ObservableCollection<T> Collection { get; private set; }
public EfObservableCollection()
{
Collection = new ObservableCollection<T>();
}
[DataMember]
public string PersistHelper
{
get
{
string serializedValue = string.Join(VALUE_SEPARATOR, Collection.ToArray());
return serializedValue;
}
set
{
Collection.Clear();
string[] serializedValues = value.Split(VALUE_SEPARATORS, StringSplitOptions.None);
foreach (string serializedValue in serializedValues)
{
Collection.Add((T)Convert.ChangeType(serializedValue, typeof(T))); // T must implement IConvertable, else a runtime exception.
}
}
}
public void Add(T item)
{
Collection.Add(item);
}
IEnumerator<T> GetEnumerator()
{
return Collection.GetEnumerator();
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
It turns out that Entity Framework does not like the generic class EfObservableCollection<T>.
If I derive a non-generic class from that class, data is persisted as expected:
[ComplexType]
public class EfObservableCollectionString : EfObservableCollection<string>
{
}
Joining backspace with list of strings causes cleaning last character in each string item.
I think serialization to json using System.Web.Script.Serialization.JavaScriptSerializer is better.

Using ValueInjecter to map between objects with different property names

How do I map a property from an object to another object with a different property name?
I have a Product class that looks like this:
public class Product : IEntity
{
public int Id { get; set; }
public string Name { get; set; }
}
And the view model looks like:
public class ProductSpecificationAddViewModel
{
public int ProductId { get; set; }
public string ProductName { get; set; }
}
I need to do the following mapping:
Product.Id => ProductSpecificationAddViewModel.ProductId
Product.Name =>ProductSpecificationAddViewModel.ProductName
Here is my action method:
public ActionResult Add(int id)
{
Product product = productService.GetById(id);
// Mapping
//ProductSpecificationAddViewModel viewModel = new ProductSpecificationAddViewModel();
//viewModel.InjectFrom(product);
return View(viewModel);
}
How would I do this?
If you are using ValueInjecter then you would write a ConventionInjection. See the second sample here
public class PropToTypeProp : ConventionInjection
{
protected override bool Match(ConventionInfo c)
{
return c.TargetProp.Name == c.Source.Type.Name + c.TargetProp.Name;
}
}
this injection will do from all properties of TSource.* to TTarget.TSource+*, so you do:
vm.InjectFrom<PropToTypeProp>(product);
You can do this easily with AutoMapper. By default is uses convention (i.e. Id maps to Id and Name to Name), but you can also define custom mappings.
Mapper.CreateMap<Product, ProductSpecificationAddViewModel>()
.ForMember(destination => destination.ProductName,
options => options.MapFrom(
source => source.Name));
Your contoller mapping code will be then this simple :
Mapper.Map(product, viewModel);

Resources