Hello to all (sorry for my bad english),
I have a strange problem: I'm using a WCF RIA Service in LightSitch 2012 (LS).
The Class Library with the WCF RIA compiles, and I'm able to use it a new Data Source in LS.
I'm able to import the tables and correctly see the relationship between tables (Navigation Properties, BUT when I compile the whole Solution I get this error:
Multiplicity is not valid in Role 'TappaEntity' in relationship 'AssocTappe'. Because the Dependent Role refers to the key properties, the upper bound of the multiplicity of the Dependent Role must be 1.
Right now the only solution is the comment the Association in the second class (TappaEntity), but I didn't try to use the Tables and I'm exprected errors..
Bellow I write my code..can someone help me please?
Thanks a lot!!!
public class GiroEntity
{
[Key(), Editable(false)]
public int IdGiro { get; set; }
[Required(ErrorMessage = "La descrizione del giro e' obbligatoria"), Editable(false), StringLength(50)]
public string DescrizioneGiro { get; set; }
[Include]
[Association("AssocTappe", "IdGiro", "IdTappa", IsForeignKey = false)]
public IQueryable<TappaEntity> Tappe { get; set; }
}
public class TappaEntity
{
[Key(), Editable(false)]
public int IdTappa { get; set; }
[Required(ErrorMessage = "La descrizione della tappa e' obbligatoria"), Editable(false), StringLength(50)]
public string DescrizioneTappa { get; set; }
[Association("AssocTappe", "IdTappa", "IdGiro", IsForeignKey = true)]
public GiroEntity Giro { get; set; }
}
O Found the answer...see the follow code
public class GiroEntity
{
[Key(), Editable(false)]
public int IdGiro { get; set; }
[Required(ErrorMessage = "La descrizione del giro e' obbligatoria"), Editable(false), StringLength(50)]
public string DescrizioneGiro { get; set; }
[Include]
[Association("AssocTappe", "IdGiro", "ParentId", IsForeignKey = false)]
//[Required(ErrorMessage = "Per il giro devono essere definite delle tappe")]
public List<TappaEntity> Tappe { get; set; }
}
public class TappaEntity
{
[Key(), Editable(false)]
public int IdTappa { get; set; }
[Required(ErrorMessage = "La descrizione della tappa e' obbligatoria"), Editable(false), StringLength(50)]
public string DescrizioneTappa { get; set; }
public int? ParentId { get; set; }
[Include]
[Association("AssocTappe", "ParentId", "IdGiro", IsForeignKey = true)]
public GiroEntity Giro { get; set; }
}
Related
I am using the latest version of Automapper (12.0).
When applying a constructor on a parent DTO, "ExplicitExpansion" does not work.
Here My Model and DTOs:
class Maestro
{
public virtual Guid Id { get; set; }
public virtual string Nombre { get; set; }
public virtual IList<Alumno> Alumnos { get; set; }
}
class Alumno
{
public virtual Guid Id { get; set; }
public virtual string Nombre { get; set; }
}
class MaestroDto
{
public MaestroDto(System.Guid id, string nombre, List<AlumnoDto> alumnos)
{
this.Id = id;
this.Nombre = nombre;
this.Alumnos = alumnos;
}
[System.ComponentModel.DataAnnotations.Key]
[System.ComponentModel.DataAnnotations.Required()]
public System.Guid Id { get; set; }
[System.ComponentModel.DataAnnotations.Required()]
public string Nombre { get; set; }
public List<AlumnoDto> Alumnos { get; set; }
}
class AlumnoDto
{
public virtual Guid Id { get; set; }
public virtual string Nombre { get; set; }
}
Please note that MaestroDto has a constructor.
This is my mapping configuration:
var config = new MapperConfiguration(c =>
{
c.CreateMap<Maestro, MaestroDto>().ForMember(c => c.Alumnos, opt => opt.ExplicitExpansion());
c.CreateMap<Alumno, AlumnoDto>();
});
config.AssertConfigurationIsValid();
var mapper = config.CreateMapper();
When making projections with Automapper in this way:
List<MaestroDto> resultMaestro = mapper.ProjectTo<MaestroDto>(maestros.AsQueryable()).ToList();
"Alumnos" is always loaded even when I have not specifically said I want it to be.
This is due to the constructor that has "MaestroDto", is this expected? I would expect that even having the constructor the property would be ignored if I wish, by not adding it in the query with the lambda expression.
Here you can find the Gist.
Thanks in advance.
Disabling mapping constructors solves the issue.
Adding cfg.DisableConstructorMapping() at the mapping initialization makes it work.
So I am dipping into EF Core a little bit and experimenting with inheritance and the TPH pattern (I have no prior experience with this). The resulting database that EF creates is not what I expected and I am wondering if it's possible to get the result I am looking for using fluent-api, or if I am just missing the point altogether.
First, here are my POCO classes:
public class Commission
{
public int Id { get; set; }
public string Description { get; set; }
public double Rate { get; set; }
}
public class Party
{
public int PartyId { get; set; }
public string Name { get; set; }
public string Address1 { get; set; }
public string Address2 { get; set; }
public string City { get; set; }
public string State { get; set; }
public string Zip { get; set; }
}
public class Agency : Party
{
public string AgencyCode { get; set; }
public ICollection<Commission> Commissions { get; set; }
}
public class Carrier : Party
{
public string CarrierCode { get; set; }
public ICollection<Commission> Commissions { get; set; }
}
public class Principal : Party
{
public string Website { get; set; }
public string DistrictCode { get; set; }
}
And my context class just in case:
public class PartyContext : DbContext
{
public DbSet<Agency> Agencies { get; set; }
public DbSet<Carrier> Carriers { get; set; }
public DbSet<Party> Parties { get; set; }
public DbSet<Commission> Commissions { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer(#"Server=LAPTOP-PC\SQLEXPRESS;Database=MyDatabase;Trusted_Connection=True;");
}
}
Basically, Agency, Carrier, and Principal all inherit from Party, so they should have all the same properties as Party. Agency and Carrier have additional specific properties, and should have a zero or one-to-many relationship with Commissions. Additionally, Principal has a couple specific properties, but has no relationship to commissions.
The resulting database is as follows:
I have no issue with the output of the Parties table itself, and understand what the discriminator field is, however I do not understand the two foreign-key relationships it created:
Parties to Commissions_AgencyPartyId
Parties to Commissions_CarrierPartyId
My question is why can't I just have one foreign key relationship from Parties to Commissions_PartyId on the back-end? And if I can, how can I tell EF to create it that way?
EDIT
Using Dmitry's suggestion and using the [InverseProperty] attribute, I ended up with the following database design which is not the desired output:
It actually made a third field (PartyId1). So I started looking at the EF documentation on relationships again and started playing with different annotations. Using the [ForeignKey("PartyId")] attribute gave me some hope after it produced the design that I am expecting:
However, this too had some unexpected effects. After trying to populate the database with an Agency and a Carrier, I receive an exception.
Here's the populating code:
PartyContext _context = new PartyContext();
// Add an Agency
var agencyCommission1 = new Commission
{
Description = "Contract",
Rate = 0.075
};
var agencyCcommission2 = new Commission
{
Description = "Hauling",
Rate = 0.10
};
var agencyCommissionList = new List<Commission>
{
agencyCommission1, agencyCcommission2
};
var agency = new Agency
{
Name = "Agency International",
Address1 = "12345 Main Street",
Address2 = "Suite 100",
City = "Chicago",
State = "IL",
Zip = "31202",
AgencyCode = "AI",
Commissions = agencyCommissionList
};
// Add Carrier
var carrierCommission1 = new Commission
{
Description = "Coal",
Rate = 0.15
};
var carrierCommission2 = new Commission
{
Description = "Mining",
Rate = 0.115
};
var carrierCommissionList = new List<Commission>
{
carrierCommission1, carrierCommission2
};
var carrier = new Carrier
{
Name = "Carrier International",
Address1 = "54321 Main Street",
Address2 = "Suite 300",
City = "Cleveland",
State = "OH",
Zip = "44115",
CarrierCode = "CI",
Commissions = carrierCommissionList
};
_context.Agencies.Add(agency);
_context.Carriers.Add(carrier);
try
{
_context.SaveChanges();
}
catch(Exception ex)
{
return;
}
The exception when adding the Agency is "Unable to cast object of type 'EFTest.Agency' to type 'EFTest.Carrier'." and the exception when trying to add the Carrier is "Unable to cast object of type 'EFTest.Carrier' to type 'EFTest.Agency'."
I will add that when using the original EF design, the program does work as expected, however the additional fields and foreign keys are making my OCD a little crazy :) Any more thoughts are welcome!
If you configure both relationships to use the same property as the foreign key you still have two relationships. So when adding a Commission with PartyIdequal to 1 EF interprets it as being related to an Agency with PartyId equal to 1 and a Carrier with PartyId equal to 1, obviously this would be impossible.
What you would need to do is create a relationship between Commission and Party, however this would mean that the Commissions navigation property would need to be moved to Party as well. But you can still hide it on Principal and other derived classes by making it protected and only exposing it on Agency and Carrier:
public class PartyContext : DbContext
{
public PartyContext(DbContextOptions options)
: base(options)
{
}
public DbSet<Agency> Agencies { get; set; }
public DbSet<Carrier> Carriers { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Party>().HasMany(typeof(Commission), "Commissions").WithOne();
}
}
public class Party
{
public int PartyId { get; set; }
protected ICollection<Commission> Commissions { get; set; }
}
public class Agency : Party
{
public new ICollection<Commission> Commissions
{
get { return base.Commissions; }
set { base.Commissions = value; }
}
}
public class Carrier : Party
{
public new ICollection<Commission> Commissions
{
get { return base.Commissions; }
set { base.Commissions = value; }
}
}
public class Commission
{
public int Id { get; set; }
}
Try this:
public class Commission
{
public int Id { get; set; }
public string Description { get; set; }
public double Rate { get; set; }
public Party Party { get; set; } // <-- "parent" party link here
}
public class Agency : Party
{
public string AgencyCode { get; set; }
[InverseProperty("Party")] // <-- link this collection with Party.Party
public ICollection<Commission> Commissions { get; set; }
}
public class Carrier : Party
{
public string CarrierCode { get; set; }
[InverseProperty("Party")] // <-- link this collection with Party.Party
public ICollection<Commission> Commissions { get; set; }
}
I'll try to explain this the best that I can so it makes sense.
I have two Models - BuyerProfile and Producerprofile
BuyerProfile
public class BuyerProfile : IAuditTrack
{
[KeyProperty(Identity = true)]
public int Id { get; set; }
[Required]
public string UserId { get; set; }
[Required]
public string Name { get; set; }
[Required]
public int BuyerTypeId { get; set; }
[Required]
public string Address { get; set; }
[Required]
public string City { get; set; }
[Required]
public string State { get; set; }
public string Zipcode { get; set; }
public string Description { get; set; }
[NonStored]
public string BuyerTypeDisplay { get; set; }
}
ProducerProfile
public class ProducerProfile : IAuditTrack
{
[KeyProperty(Identity = true)]
public int Id { get; set; }
[Required]
public string UserId { get; set; }
[Required]
public string Name { get; set; }
[Required]
public string Address { get; set; }
[Required]
public string City { get; set; }
[Required]
public string State { get; set; }
public string Zipcode { get; set; }
public string Description { get; set; }
}
I have a simple method on my controller that retrieves all of the profiles in the database and concatenates them together.
[HttpGet]
public JsonResult GetAllProfiles()
{
var buyerProfiles = _profileService.GetAllBuyerProfiles();
var producerProfiles = _profileService.GetAllProducerProfiles();
var profiles = buyerProfiles.Concat(producerProfiles);
return Json(profiles, JsonRequestBehavior.AllowGet);
}
Now what I would like to do is be able to find every BuyerProfile and ProducerProfile that share the same UserId and merge them together into a new model that would look like this:
public class BuyerProducerprofile
{
public string UserId { get; set; }
public string BuyerName { get; set; }
public string ProducerName { get; set; }
}
The current system that I'm building only allows users to complete 1 BuyerProfile and 1 ProducerProfile.
So for example, in the result set I might have a BuyerProfile that contains the following information:
Id -> 1543
UserId -> abc123
Name -> Bob's Buying Company
and a ProducerProfile that contains the following information:
Id -> 1678
UserId -> abc123
Name -> Bob's Produce Company
I would like to be able to combine the two into my new model so that it looks something like this:
UserId -> abc123
BuyerName -> Bob's Buying Company
ProducerName -> Bob's Produce Company
I'm not sure if this is at all possible without using some kind of Nuget package but it would be awesome if I didn't have to use one that I don't already have.
I also am currently using AutoMapper to do some of my mapping but I couldn't find any documentation that shows being able to use it to do this.
what you want to do is called a join. you can do it like this
var buyerProfiles = _profileService.GetAllBuyerProfiles();
var producerProfiles = _profileService.GetAllProducerProfiles();
var combinedProfiles =
from bp in buyerProfiles
join pp in producerProfiles on bp.UserId equals pp.UserId
select new BuyerProducerprofile()
{
UserId = pp.UserId,
BuyerName = bp.Name,
ProducerName = pp.Name
}
note: if the same user can have more than one of a type of profile, this will return a result for every combination of buyer profile and producer profile that can be made for that user.
other note: this is what is called an "inner join", and it will only give you results for users that have both profiles. You can do other kinds of joins too, but syntax for those joins doesn't feel very natural, and I don't have them committed to memory. I'm sure a google search can find the syntax for you.
I have problems with gerenating types, it returns error
500 - InvalidDataException
I can't understand whats wrong as my project builds fine and API works.
None of the types works except the metadata
https://testapi.bokamera.se/types/
Please help as i'm stuck
Regards Kristian
Here you can see my call using Postman
and here you can see my DTO causing the problem
namespace BokaMera.API.ServiceModel.Dtos
{
[Route("/customfields",
Verbs = "GET",
Summary = "Find custom fields",
Notes =
"Find custom fields defined for the bookings that the current admin user is authorized to view."
)]
[ApiResponse(HttpStatusCode.Unauthorized, "You were unauthorized to call this service")]
[ApiResponse(HttpStatusCode.Forbidden, "You have too low privilegies to call this service")]
public class CustomFieldQuery :
QueryBase<CustomFieldConfig, CustomFieldQueryResponse>
{
[ApiMember(
Description =
"One or multiple id's of custom fields to find",
ParameterType = "query",
IsRequired = false)]
public int[] Ids { get; set; }
[ApiMember(
Description =
"Company id to find custom fields for",
ParameterType = "query",
IsRequired = false)]
public Guid? CompanyId { get; set; }
[ApiMember(
Description =
"Table to which the custom field belongs to",
ParameterType = "query",
IsRequired = false)]
public string Table { get; set; }
[ApiMember(
Description =
"Active or removed fields, empty parameter includes both",
ParameterType = "query",
IsRequired = false)]
public bool? Active { get; set; }
}
public class CustomFieldQueryResponse
{
[ApiMember(Description = "Custom field id")]
public int Id { get; set; }
[ApiMember(Description = "Reference to company that owns the custom field configuration")]
public Guid CompanyId { get; set; }
[ApiMember(Description = "Group id")]
public int? GroupId { get; set; }
[ApiMember(Description = "Config id")]
public int ConfigId { get; set; }
[ApiMember(Description = "Configuration name. Example: \"Number of persons\".")]
public string ConfigName { get; set; }
[ApiMember(Description = "Field width. Example: 20")]
public int Width { get; set; }
[ApiMember(Description = "Column in database where to store the information. Example: \"TextField1\"")]
public string Column { get; set; }
[ApiMember(Description = "Custom field description. Example: \"For how many persons is this booking?\"")]
public string Description { get; set; }
[ApiMember(Description = "Data field of custom field. Valid values are: TextBox, ... Example: \"TextBox\"")]
public string DataType { get; set; }
[ApiMember(Description = "Default value of the field. Example: \"3\"")]
public string DefaultValue { get; set; }
[ApiMember(Description = "Determines if the field is required to have a value or not")]
public bool Required { get; set; }
[ApiMember(Description = "Error message shown to the user if the field data is required but not entered")]
public string MandatoryErrorMessage { get; set; }
[ApiMember(Description = "Max lenght of the field")]
public int MaxLength { get; set; }
[ApiMember(Description = "")]
public bool MultipleLineText { get; set; }
[ApiMember(Description = "Regular expression used for validation of the field")]
public string RegEx { get; set; }
[ApiMember(Description = "Error message shown if the regular expression validation failed")]
public string RegExErrorMessage { get; set; }
[ApiMember(Description = "If the custom field is active or have been removed")]
public bool Active { get; set; }
[ApiMember(Description = "Table to which the field belongs")]
public string Table { get; set; }
[ApiMember(Description = "")]
public List<CustomFieldLookupResponse> Values { get; set; }
}
[Alias("V_FreeFieldFieldLookUp")]
public class CustomFieldLookupResponse
{
[PrimaryKey]
[Alias("FieldLookupId")]
public int? Id { get; set; }
[Alias("FreeFieldId")]
public int CustomFieldId { get; set; }
[Alias("FieldlookupActive")]
public bool? Active { get; set; }
[Alias("FieldLookupGroupId")]
public int GroupId { get; set; }
[Alias("FieldlookupSortOrder")]
public int? SortOrder { get; set; }
[Alias("FieldlookupValue")]
public string Value { get; set; }
}
//Used when sending in values on a DTO request object to the services to save on the tables.
public class CustomFieldDataValue
{
public int Id { get; set; }
public string Column { get; set; }
public string Value { get; set; }
}
//Used to list all values on a DTO response object
public class CustomFieldData
{
public int Id { get; set; }
public string Column { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public string Value { get; set; }
}
//Used when post or put values for different DTOS, see example Resource Dtos
public class AddCustomField
{
public int Id { get; set; }
public string Value { get; set; }
}
}
And my service
namespace BokaMera.API.ServiceInterface.Services
{
public class CustomFieldService : AppServiceBase
{
public IAutoQueryDb AutoQuery { get; set; }
[Authenticate]
[RequiredRole(Role.ApplicationAdmin)]
public object Get(CustomFieldQuery request)
{
// Get the autoquery that we will append to
var q = AutoQuery.CreateQuery(request, Request.GetRequestParams());
// The user can only see his/her own time exceptions
q = q.Where(te => te.CompanyId == UserSession.CompanyId);
// Execute counts and return the query response
var response = AutoQuery.Execute(request, q);
return response;
}
}
}
If you were on v4.0.58, it had an issue with Add ServiceStack Reference which can be resolved by upgrading to any release after that.
The issue with your DTOs was because they contained illegal " character in the Metadata attributes, i.e:
[ApiMember(Description = "Configuration name. Example: \"Number of persons\".")]
public string ConfigName { get; set; }
We validate metadata attributes to prevent an attacker from potentially injecting illegal data that they could use to generate malicious in Service consumers.
So to prevent the error you can remove double quotes (") from strings in your metadata attributes, replacing them with single quotes (') is fine, otherwise you can disable token verification in your AppHost.Configure() with:
NativeTypesFeature.DisableTokenVerification = true;
Incidentally Exception details from Code Generation will be more visible in the next release from this commit, so it will be clearer to tell what the error was.
Deprecated Warnings
Please take note of the Deprecation messages (also covered in Breaking changes in each Release Notes). QueryBase has been renamed to QueryDb, e.g:
public class CustomFieldQuery :
QueryDb<CustomFieldConfig, CustomFieldQueryResponse>
Also it's better for your custom AutoQuery implementations to pass the entire IRequest instead of just the parameters, e.g:
var q = AutoQuery.CreateQuery(request, base.Request);
This has the same behavior except it also allows this AutoQuery Service to participate in Multitenancy requests.
I have a following object as a model in project:
AbstractControll and AntivirusControll which inherits from AbstractControll.
public class AntivirusControll: AbstractControll
AnticvirusControll has property:
public List<Exclusion> Exclusions { get; set; }
And this part of code drives me creazy:
var a = _entities.AntivirusControlls.First(m => m.Id == 1);
var b = _entities.AbstractControlls.First(m => m.Id == 1);
In database AnticvirusControll has one exception,while in result of executing above code I get:
a.Exclusions - has one object ( which is great and ok )
b.Exclusions - has none!
How is it even called inheritance? It's not polymorphic, it's .... a bug I could tell. Lazy loading wont work in this case.
And while asking for AbstractControlls I Can't include any property from derivered class offcourse.
Any ideas how to fix it?
--EDIT
both classes;
public abstract class AbstractControll
{
public int Id { get; set; }
}
public abstract class AbstractControll
{
public int Id { get; set; }
}
public class AntivirusControll: AbstractControll
{
public class Exclusion
{
public int Id { get; set; }
[DataMember]
[Display(Name = "Object Type")]
public String ObjectType { get; set; }
[DataMember]
[Display(Name = "Object Type")]
public String ObjectName { get; set; }
[DataMember]
public ConfigurationItemDescription ExlusionCI { get; set; }
}
[Display(Name= "Is Antyvirus Enabled")]
[DataMember]
public bool? isAntyvirusEnabled { get; set; }
[DataMember]
public ConfigurationItemDescription isAntyvirusEnabledCI { get; set; }
[DataMember]
[Display(Name = "Is real time protection enabled")]
public bool? isRealTimeProtectionEnabled { get; set; }
[DataMember]
public ConfigurationItemDescription isRealTimeProtectionEnabledCI { get; set; }
[DataMember]
[Display(Name = "Virus definition not older than( in days)")]
[Required]
[Range(typeof(int),"1","365")]
public int? VirusDefinitionNotOlderThen { get; set; }
[DataMember]
public ConfigurationItemDescription VirusDefinitionNotOlderThenCI { get; set; }
[DataMember]
public List<Exclusion> Exclusions { get; set; }
public AntivirusControll()
{
isAntyvirusEnabled = true;
isRealTimeProtectionEnabled = true;
VirusDefinitionNotOlderThen = 7;
isAntyvirusEnabledCI = new ConfigurationItemDescription();
isRealTimeProtectionEnabledCI = new ConfigurationItemDescription();
VirusDefinitionNotOlderThenCI = new ConfigurationItemDescription();
Exclusions = new List<Exclusion>();
}
}
--Edit 2
Well... I wanto to clarify, what actualy I'm doing.
I have MVC + angular Application.
There is a document with some Controls( AbstractControll)
Each of them is specific Type for example: Antivirus, Encryption and so on. At this point I have about 20 of them, but I will have more probably. Most of those derived classes have inner classes like Exceptions in Antivirus.
Right.
Basicaly that's it. What is important- After getting "AbstractControll" I want to expose this object over webapi - so lazy loading is not applicable here( or maybe it could be?)
That's it. It runtime I don't know exat type of the controll, so I Can't Include Properties from for example "Antivirus", when operating on DbSet
What I have now is ugly if's block that returns propper object and includes everything, but i'm not happy about his "hack".