Mapping "long" to create an object - automapper

iam trying to map just a long field coming from my url route to create a Query Object from my controller, can i use auto mapper
CreateMap(MemberList.None);
Source :-long id
Destination:-
public class GetPlanQuery : IRequest<PlanDto>
{
public long Id { get; }
public GetPlanQuery(long id)
{
Id = id;
}
internal sealed class GetPlanQueryHandler : IRequestHandler<GetPlanQuery, PlanDto>
{
//Logic will go here
}
}
Map i am using is as below
CreateMap<long, GetPlanQuery>(MemberList.None);
i am getting an exception while executing as
System.ArgumentException:
needs to have a constructor with 0 args or only optional args.'

As Lucian correctly suggested you can achieve this kind of custom mapping by implementing ITypeConverter:
public class LongToGetPlanQueryTypeConverter : ITypeConverter<long, GetPlanQuery>
{
public GetPlanQuery Convert(long source, GetPlanQuery destination, ResolutionContext context)
{
return new GetPlanQuery(source);
}
}
then specify it's usage in AutoMapper configuration:
configuration.CreateMap<long, GetPlanQuery>()
.ConvertUsing<LongToGetPlanQueryTypeConverter>();
EDIT
Alternatively, you can just use a Func:
configuration.CreateMap<long, GetPlanQuery>()
.ConvertUsing(id => new GetPlanQuery(id));

Related

Load catalogs from external DB and link them to ContentParts as ContentRecords

Example: I have a countries catalog stored in another DB and I need to use it as a property in some ContentParts. I'm trying to make the connection without interfering much with Orchard wiring.
public class MoviePart : ContentPart<MoviePartRecord>
{
public IEnumerable<CountryRecord> Countries
{
get
{
return Record.Countries.Select(r => r.CountryRecord);
}
}
}
The relation between CountryRecords and MovieParts will be on the Orchard DB, but the CountryRecord data is in another DB. I only need Read access, but I don't get which and how to override the Handler to use the other source.
Do I need to create a ContentHandler and override all methods, and create another StorageFilter that uses the new repository with the external source? And how would I inject the new repo into the handler?
public class CountryPartHandler : ContentHandler
{
public CountryPartHandler(IRepository<CountryPartRecord> repository)
{
Filters.Add(StorageFilter.For(repository));
}
protected override void Loading(LoadContentContext context)
{
base.Loading(context);
}
}
Update:
In this Using External Data with Orchard (around 25th min) video, he seems to be doing what I need with this code:
public ProductPartHandler(IRepository<ProductPartRecord> repository, Work<IProductService> productServiceWork)
{
Filters.Add(StorageFilter.For(repository));
OnActivated<ProductPart>((context, part) => {
part.ProductField.Loader(() => productServiceWork.Value.GetProduct(part.Id));
});
}
But in my code it can't find the "Loader" function, even though I have all the references from the video too, so maybe ProductField is a custom type?
So that is a lazy field on the part, something like this:
public class MyPart : ContentPart {
internal readonly LazyField<CustomData> CustomDataField = new LazyField<CustomData>();
public CustomData CustomData {
get { return CustomDataField.Value; }
}
}
public class CustomData {
...
}
public class MyPartHandler : ContentPartHandler {
private ICustomService _customService;
public MyPartHandler(ICustomService customService){
_customService = customService;
OnActivated<MyPart>(Initialize);
}
private void Initialize(ActivatedContentContext context, MyPart part){
part.CustomDataField.Loader(() => {
return _customService.Get(part.ContentItem.Id);
});
}
}
I don't know how you are loading your external data, whether via rest, wcf etc., but the logic can just be thrown into the custom service

Orchard Query For Page with Show on a menu checked

Hi I want to make a "Query" and put a filter for returning all pages that has "Show on a menu" checked. I did not find a way to do that.. Is it possible?
Try something like this:
using Orchard.Localization;
using Orchard.Projections.Descriptors.Filter;
using Orchard.Navigation;
using IFilterProvider = Orchard.Projections.Services.IFilterProvider;
namespace MyProject.Filters
{
public class MenuPartFilter : IFilterProvider {
public Localizer T { get; set; }
public ProductPartFilter() {
T = NullLocalizer.Instance;
}
public void Describe(DescribeFilterContext describe)
{
describe.For(
"Content", // The category of this filter
T("Content"), // The name of the filter (not used in 1.4)
T("Content")) // The description of the filter (not used in 1.4)
// Defines the actual filter (we could define multiple filters using the fluent syntax)
.Element(
"MenuParts", // Type of the element
T("Menu Parts"), // Name of the element
T("Menu parts"), // Description of the element
ApplyFilter, // Delegate to a method that performs the actual filtering for this element
DisplayFilter // Delegate to a method that returns a descriptive string for this element
);
}
private void ApplyFilter(FilterContext context) {
// Set the Query property of the context parameter to any IHqlQuery. In our case, we use a default query
// and narrow it down by joining with the MenuPartRecord.
context.Query = context.Query.Join(x => x.ContentPartRecord(typeof (MenuPartRecord)));
}
private LocalizedString DisplayFilter(FilterContext context) {
return T("Content with MenuPart");
}
}
}

AutoMapper ConstructServicesUsing is ignored

I have a Person and a PersonViewModel. I created a map from Person => PersonViewModel. The problem is that PersonViewModel's only constructor needs an argument (it has a dependency that I want to be injected) and AutoMapper is complaining because it says it needs a parameterless constructor.
To fix it, I used the ConstructServicesUsing method, but I haven't been successful with it :(
To illustrate the case, I created a test for you to see what I'm doing. It's pretty simple:
[TestMethod]
public void TestConstructServicesUsing()
{
Mapper.Initialize(configuration =>
{
configuration.ConstructServicesUsing(FactoryMethod);
configuration.CreateMap<Person, PersonViewModel>();
});
Mapper.AssertConfigurationIsValid();
var person = new Person();
var personViewModel = Mapper.Map<Person, PersonViewModel>(person);
}
private object FactoryMethod(Type type)
{
throw new NotImplementedException();
}
}
The rest of the code is the classes and interface definitions. They are almost empty.
public class SomeyDependency : ISomeDependency
{
}
public class PersonViewModel
{
private readonly ISomeDependency service;
public PersonViewModel(ISomeDependency service)
{
this.service = service;
}
public string Name { get; set; }
}
public class Person
{
public string Name { get; set; }
}
public interface ISomeDependency
{
}
As you see, I provide AutoMapper with a FactoryMethod, but it never get called.
When it reaches the last line of the test (Mapper.Map<...>()) it throws an excepton saying:
AutoMapper.AutoMapperMappingException:
Mapping types:
Person -> PersonViewModel
MappingWithContainerTests.Person -> MappingWithContainerTests.PersonViewModel
Destination path:
PersonViewModel
Source value:
MappingWithContainerTests.Person ---> System.ArgumentException: Type needs to have a constructor with 0 args or only optional args
Parameter name: type
What's the problem?
Why isn't the FactoryMethod being called?
As #khorvat mention where is missing .ConstructUsingServiceLocator(), for concrete mapping.
Also you can set constructor directly by
.ConstructUsing(source => Method(source.anySourceOptions))
Or as exception said:
PersonViewModel, must have a constructor with 0 args or only optional
args. You have only one constructor with 1 not optional argument
you may create one more constructor without args:
public PersonViewModel()
{
this.service = new SomeDependency();
}
I'm using .NET Core 3.1 and Automapper.Extensions.Microsoft.DependencyInjection.
This does not work for me (Same error as yours):
public class AutoMapping : Profile
{
public AutoMapping()
{
CreateMap<Context, MainViewModel>()
.ReverseMap()
.ConstructUsingServiceLocator();
}
}
But this does work:
public class AutoMapping : Profile
{
public AutoMapping()
{
CreateMap<Context, MainViewModel>()
.ConstructUsingServiceLocator()
.ReverseMap();
}
}
I still do not fully understand the cause.

How to set up Entity Framework to map two classes to the same table

I've been bumbling along with EF5 but I cant seem to get two domain classes to map to a single database table.
The error I get is:
Message: "The type 'Basd.Erp.Wms.Purchasing.SupplierProfile' has already been configured as an entity type. It cannot be reconfigured as a complex type."
This is my DbContext:
public class PurchasingContext : DisconnectedEntityContext
{
public DbSet<SupplierCard> Suppliers { get; set; }
public DbSet<PurchaseCategory> PurchaseCategories { get; set; }
public PurchasingContext() : this("Basd.Erp.Wms") { }
public PurchasingContext(string connectionStringName) : base(connectionStringName) { }
public static PurchasingContext GetInstance(EfDataProvider provider) { return new PurchasingContext(provider.ConnectionStringName); }
}
}
These are my classes:
namespace Basd.Erp.Wms.Purchasing
{
public class SupplierCard : ContactCard, ISupplierCard
{
private ICollection<PurchaseCategory> _purchaseCategories;
public ICollection<PurchaseCategory> PurchaseCategories
{
get { return _purchaseCategories; }
set { SetNotifyField(ref _purchaseCategories, value, () => PurchaseCategories); }
}
public SupplierProfile Profile { get; protected set; }
private SupplierCard()
{
this.Profile = new SupplierProfile();
this.PurchaseCategories = new Collection<PurchaseCategory>();
}
public SupplierCard(long id, string alf, string name)
: this(id, alf, new SimpleNameHolder(name), new Collection<IPhysicalAddress>(), new DigitalAddresses()) { }
public SupplierCard(long id, string alf, INameHolder nameHolder,
ICollection<IPhysicalAddress> physicalAddresses, IDigitalAddresses digitalAddresses)
: this(id, alf, nameHolder, physicalAddresses, digitalAddresses, null) { }
public SupplierCard(long id, string alf, INameHolder nameHolder,
ICollection<IPhysicalAddress> physicalAddresses, IDigitalAddresses digitalAddresses, IValidatableObject validator)
: base(id, alf, nameHolder, physicalAddresses, digitalAddresses, validator)
{
this.Profile = new SupplierProfile();
this.PurchaseCategories = new Collection<PurchaseCategory>();
}
}
}
public class SupplierProfile : AbstractAspect
{
private TradingEntity _incType;
public TradingEntity BusinessType
{
get { return _incType; }
set
{
if (_incType != null) { this.DeregisterSubPropertyForChangeTracking(this.BusinessType); }
_incType = value; this.OnPropertyChanged("TradingType");
this.RegisterSubPropertyForChangeTracking(this.BusinessType);
}
}
private bool _emailOk;
private bool _smailOk;
public bool MarketingEmailOk
{
get { return _emailOk; }
set { _emailOk = value; this.OnPropertyChanged("MarketingEmailOk"); }
}
public bool MarketingSmailOk
{
get { return _smailOk; }
set { _smailOk = value; this.OnPropertyChanged("MarketingSmailOk"); }
}
public SupplierProfile()
: base()
{
this.BusinessType = new TradingEntity(ContactLegalType.Limited);
}
}
}
These are my configuration classes:
[Export(typeof(IEntityConfiguration))]
public class SupplierCardConfiguration
: EntityTypeConfiguration<SupplierCard>, IEntityConfiguration
{
public SupplierCardConfiguration()
{
this.ToTable("SupplierCard", "erp_wms");
HasKey(u => u.Id);
Property(u => u.Id).HasColumnName("SupplierId");
Ignore(u => u.UsePropertyNotifications);
Property(u => u.Profile.MarketingEmailOk).HasColumnName("MarketingEmailOk");
HasMany(i => i.PurchaseCategories)
.WithMany(c => c.Suppliers)
.Map(mc =>
{
mc.MapLeftKey("CategoryId");
mc.MapRightKey("SupplierId");
mc.ToTable("SupplierPurchaseCategory", "erp_wms");
});
}
public void AddConfiguration(ConfigurationRegistrar registrar)
{
registrar.Add(this);
}
}
[Export(typeof(IEntityConfiguration))]
public class SupplierProfileConfiguration
: EntityTypeConfiguration<SupplierProfile>, IEntityConfiguration
{
public SupplierProfileConfiguration()
{
this.ToTable("SupplierCard", "erp_wms");
Ignore(u => u.UsePropertyNotifications);
Property(u => u.MarketingEmailOk).HasColumnName("MarketingEmailOk");
}
public void AddConfiguration(ConfigurationRegistrar registrar)
{
registrar.Add(this);
}
}
UPDATE:
Ok so Ive tried ignoring SupplierProfile as per suggestion that changed nothing. I then tried removing the configuration class for Supplier Profile and left
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Ignore<SupplierProfile>();
base.OnModelCreating(modelBuilder);
}
and that generated an error:
{"The property 'Profile' is not a declared property on type
'SupplierCard'. Verify that the property has not been explicitly
excluded from the model by using the Ignore method or
NotMappedAttribute data annotation. Make sure that it is a valid
primitive property."}
[System.InvalidOperationException]: {"The property 'Profile' is not a declared property on type 'SupplierCard'. Verify that the
property has not been explicitly excluded from the model by using the
Ignore method or NotMappedAttribute data annotation. Make sure that it
is a valid primitive property."}
I then tried removing the
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Ignore<SupplierProfile>();
base.OnModelCreating(modelBuilder);
}
while leaving out the configuration class for SupplierProfile and that generates the error:
Message: "Invalid column name
'Profile_BusinessType_ContactLegalType'.\r\nInvalid column name
'Profile_BusinessType_TradingSince'.\r\nInvalid column name
'Profile_BusinessType_State'.\r\nInvalid column name
'Profile_BusinessType_UsePropertyNotifications'.\r\nInvalid column
name 'MarketingEmailOk'.\r\nInvalid column name
'Profile_MarketingSmailOk'.\r\nInvalid column name
'Profile_State'.\r\nInvalid column name
'Profile_UsePropertyNotifications'.\r\nInvalid column name
'OwnerId'.\r\nInvalid column name 'State'."
So like I said, just **bumbling** along ;)
After reading this I think it might have something to do with your relationship in your SupplierCard class.
public class SupplierCard : ContactCard, ISupplierCard
{
public SupplierProfile Profile { get; protected set; }
}
I'm guessing it registering as a complex type when SupplierCard is mapped.
A suggested way to fix it is to ignore it.
modelBuilder.Ignore<SupplierProfile>();
I've never run into this problem myself, so not sure if this'll help.
So after a lot of mucking around it turns out the underlying problem is a bug in Entity Framework 5. This bug has been fixed in EF6 beta. All other errors were in fact just masking this underlying error.
The following explaination is not terribly good as I dont fully understand it myself.
Short answer is: Use EF6 or otherwise modify EF5 source code.
Turns out that if you have a class in assembly B, that has a property of a type of enum defined in Assembly A, EF5 gets confused and thinks the enum is missing or somehow unavailable and sets about trying to generate the type itself.
So I had:
Assembly A containing enum type AA.
Assembly B referencing Assembly A so a contained class BB could have a property of type AA.
An EF5 data layer Assembly referencing both Assembly A & B.
An EF5 configuration layer Assembly referencing both Assembly A & B.
And it failed.
But if I "simply" move enum type AA into Assembly B then everything works.
This is of course is completely useless because then I set up all kinds of dependencies on Assembly B for any Assembly that has a member who needs an enum AA. But that is the test.
To top it off there also appears to be some particular set of circumstances in which everything I just said does not apply due to the order assemblies are loaded at runtime. The order of this loading cannot be forced i.e. it's non-determinant so it's pot luck.

Do Azure table services entities have an equivalent of NonSerializedAttribute?

If I'm trying to serialize a normal CLR object, and I do not want a particular member variable to be serialized, I can tag it with the
[NonSerialized]
attribute. If I am creating a table services entity, is there an equivalent attribute I can use to tell Azure table services to ignore this property?
For Version 2.1 there is a new Microsoft.WindowsAzure.Storage.Table.IgnoreProperty attribute. See the 2.1 release notes for more information: http://blogs.msdn.com/b/windowsazurestorage/archive/2013/09/07/announcing-storage-client-library-2-1-rtm.aspx.
There's no equivalent I know of.
This post says how you can achieve the desired effect - http://blogs.msdn.com/b/phaniraj/archive/2008/12/11/customizing-serialization-of-entities-in-the-ado-net-data-services-client-library.aspx
Alternatively, if you can get away with using "internal" rather than "public" on your property then it will not get persisted with the current SDK (but this might change in the future).
For version 2.0 of the Table Storage SDK there is a new way to achieve this.
You can now override the WriteEntity method on TableEntity and remove any entity properties that have an attribute on them. I derive from a class that does this for all my entities, like:
public class CustomSerializationTableEntity : TableEntity
{
public CustomSerializationTableEntity()
{
}
public CustomSerializationTableEntity(string partitionKey, string rowKey)
: base(partitionKey, rowKey)
{
}
public override IDictionary<string, EntityProperty> WriteEntity(Microsoft.WindowsAzure.Storage.OperationContext operationContext)
{
var entityProperties = base.WriteEntity(operationContext);
var objectProperties = this.GetType().GetProperties();
foreach (PropertyInfo property in objectProperties)
{
// see if the property has the attribute to not serialization, and if it does remove it from the entities to send to write
object[] notSerializedAttributes = property.GetCustomAttributes(typeof(NotSerializedAttribute), false);
if (notSerializedAttributes.Length > 0)
{
entityProperties.Remove(property.Name);
}
}
return entityProperties;
}
}
[AttributeUsage(AttributeTargets.Property)]
public class NotSerializedAttribute : Attribute
{
}
Then you can make use of this class for your entities like
public class MyEntity : CustomSerializationTableEntity
{
public MyEntity()
{
}
public string MySerializedProperty { get; set; }
[NotSerialized]
public List<string> MyNotSerializedProperty { get; set; }
}

Resources