I have a class like this:
public class Empresa
{
public string Nombre { get; set; }
public string NIT { get; set; }
public string NombreRepresentanteLegal { get; set; }
public string TelefonoRepresentanteLegal { get; set; }
public string NombreContacto { get; set; }
public string TelefonoContacto { get; set; }
}
However in my app, I want the users to be able to add custom properties, for example twitter handle, however I havent found documentation in how to do that, I heard about the EAV model, but thats not performant
You could store the additional data as XML into an XML column, and have the client deserialize / serialize the meta-data appropriately. Xml can be a viable solution for when you don't know the structure of the data, or if the structure can be altered at run-time.
You're also able to INDEX the XML to help with shredding / querying, so performance can be maintained while processing large xml documents.
Your class could contain, an ExtraPropertiesElement, that takes the XML string, and parses it into an XElement, which you could then utilize XPath, to query for the requested xml element/attribute.
One problem with this approach, is that all additional properties are stored in XML in the database, and it's not as easy to perform queries against the data. It's straightforward to do so, but it's not as simple as selecting a column name from a table.
You can read more about the XML Data Type and the uses here.
You can also read up on how to query XML column stores here.
public class Empresa
{
public string Nombre { get; set; }
public string NIT { get; set; }
public string NombreRepresentanteLegal { get; set; }
public string TelefonoRepresentanteLegal { get; set; }
public string NombreContacto { get; set; }
public string TelefonoContacto { get; set; }
[Column(TypeName="xml")]
public string ExtraProperties { get; set; }
[NotMapped]
public XElement ExtraPropertiesElement
{
get { return XElement.Parse(ExtraProperties ); }
set { ExtraProperties = value.ToString(); }
}
}
Related
I am a bit stuck, hoping for guidance. I have 2 tables, Header and Details. However, the details is a bit different than most, and allows for a way to dynamically store data.: Yes, I am aware that I can create a table storing the details in the standard fashion, but the nature of the app needs to be more dynamic on the database side. I also realize I will have to modify the DTOs for different incarnations of the app, but this model is what I need to accomplish.
public class Header
{
public int Id { get; set; }
public string HeaderName { get; set; }
public ICollection<Detail> Details { get; set; }
}
public class Detail
{
public int Id { get; set; }
public int HeaderId { get; set; }
public string FieldName { get; set; }
public string FieldProperty { get; set; }
}
I want to use the following DTOs:
public class DataForDisplayDto
{
public int Id { get; set; }
public string HeaderName { get; set; }
public string TaskToPerform { get; set; }
public string Location { get; set; }
}
public class DataForCreationDto
{
public string HeaderName { get; set; }
public string TaskToPerform { get; set; }
public string Location { get; set; }
}
The data would be stored in the details in this fashion:
{
"FieldName": "tasktoperform",
"FieldProperty": "Thing to Do"
},
{
"FieldName": "location",
"FieldProperty": "Over there"
}
I am trying to use the Automapper to make it so I can read and write to the database using the DTOs, but I think I may be trying something it can't do.
Is there an article or something that anyone knows about that can point me in the direction to go? Or even the right keywords to search online for it. Is it even possible?
I suppose if it is not possible, I will have to do things a bit more manually, which is the last option, I am just hoping to do this with Automapper.
Thanks!
How about deriving your DTO from a base class that uses reflection to generate a mapping, and cache that mapping.
This way your DTO need only inherit a base class.
I have a sqlite database which has some tables and columns like the following:
int Id
text Name
text Comment
...
And my object in my project looks like this:
Public Class Entry {
public int Id { get; set; }
public String Name { get; set; }
public String Comment { get; set; }
public String Additional { get; set; }
}
This can happen, because my programm need to handle different versions of the database.
EF Core now trys to access the Additional field of the database but returns an error that it cannot find the field. (Expected behaviour)
Now my question is, if there is a way to ignore this error and return a default value for the property?
I could bypass the error by making the properties nullable. But i don't want to check each property with .HasValue() before accessing it. Because the real database has 50+ columns in the table.
https://www.entityframeworktutorial.net/code-first/notmapped-dataannotations-attribute-in-code-first.aspx
Put NotMapped as an attribute on the Additional field:
using System.ComponentModel.DataAnnotations.Schema;
Public Class Entry {
public int Id { get; set; }
public String Name { get; set; }
public String Comment { get; set; }
[NotMapped]
public String Additional { get; set; }
}
This tells EF that the field is not a column in the database.
I would advise you to split your domain object from that persisted dto object. That way you can have different dtos with different mappings. Now you can instantiate your domain object with your dto and decide inside your domain object what values are the correct default values.
public class Entry
{
public int Id { get; set; }
public string Name { get; set; }
public string Comment { get; set; }
public string Additional { get; set; }
}
public class EntryDtoV1
{
public int Id { get; set; }
public string Name { get; set; }
public string Comment { get; set; }
}
public class EntryDtoV2
{
public int Id { get; set; }
public string Name { get; set; }
public string Comment { get; set; }
public string Additional { get; set; }
}
Now you only need to create some kind of factory that creates the correct repository depending on what database version you query.
So I am using one of the google Id API; https://developers.google.com/instance-id/reference/server#manage_registration_tokens_for_push_subscriptions
I have previously been fortunate to have API that had WDSL or similar and been easy to parse into a class.
But the JSON I got back I can not parse easily.
{
"connectDate":"2018-02-12",
"application":"com.chrome.windows",
"subtype":"wp:https://xxxxxxxxxxxxxxxxxxx",
"authorizedEntity":"xxxxxx",
"rel":{
"topics":{
"movies":{
"addDate":"2018-01-26"
},
"anotherTopic":{
"addDate":"2018-02-12"
}
}
},
"connectionType":"WIFI",
"platform":"WEBPUSH"
}
Movies and anotherTopics are the topics I created so I can't add them to my class . Or can I?
There are of course ways to do it treating the json as string and using regex or going through the node as a dynamic object (dynamic dyn = JsonConvert.DeserializeObject(content);) but ideally I think it should be a dictionary (I think at least) but can not see how.
And as this is Google I assume there is more standard way to handle this kind of JSON.
I have tried creating a dictionary which I couldn't get working.
Stepping through the nodes I can get the data but end up with code like
DateTime.Parse(((Newtonsoft.Json.Linq.JValue)((Newtonsoft.Json.Linq.JProperty)((Newtonsoft.Json.Linq.JContainer)(obj.First)).First).Value).Value.ToString())
I have tried to look for similar JSON parsing exampels but I can not find any.
I did not share my attempt to extract the data in my first edit as I don't think that is the way to do it; it is a hack.
I created a class for it
public class SubscriptionDetails
{
public DateTime connectDate { get; set; }
public string application { get; set; }
public string subtype { get; set; }
public string authorizedEntity { get; set; }
public string connectionType { get; set; }
public string platform { get; set; }
public topics rel { get; set; }
}
But I am stuck when it comes to defining the subclass topics.
So I tried
public class topics : Dictionary<string, object>
which results in one dictionary entry with key topics?
the other option requires a dictionary name
public class topics
{
public Dictionary<string, Dictionary<string, string>> DUMMY { get; set; }
}
So thanks to the suggestion from Jamiec I got on the right track.
Of course already the node rel is a dictionary with one item called topics.
So need a few classes to parse the entire thing:
public class SubscriptionDetails
{
public DateTime connectDate { get; set; }
public string application { get; set; }
public string subtype { get; set; }
public string authorizedEntity { get; set; }
public string connectionType { get; set; }
public string platform { get; set; }
public Dictionary<string, topicItems> rel { get; set; }
}
public class topicItems : Dictionary<string, topicData> { }
public class topicData
{
public DateTime addDate { get; set; }
}
But if they add another node to rel in addition to 'topics' this most likely will crash.
Just doesn't seem to be a very good way to structure the data and the deserialised class isn't very user friendly either..
Anyway it works (for now)
I am working in C#, Visual Studio 2015, targeting .NET 4.5. We have existing systems (some written in Java, some legacy code in C++, etc.) that already exchange XML in particular formats. I have studied XMLSerializer, DataContractSerializer, and looked briefly at the ISerializable Interface. While I think I already know the answer (ISerializable), I figured I would see if anyone has any clever ideas or solutions for duplicating the XML format we need without coding it all ourselves. We have four different XML messages to duplicate, here is just one of them:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE message SYSTEM "work_request_20.dtd">
<message message_id="1005" message_dt="01/21/2008 09:50:23.221 AM" message_type="Work_Request" message_sub_type="New" message_dtd_version_number="2.0">
<header>
<from_application_id>3367e115-c873-4ac9-a1dd-7e45231dc3d5</from_application_id>
<to_application_id>35e0cca2-e423-4ffe-ba07-7d056775c228</to_application_id>
</header>
<body>
<work_request requisition_number="REQ44">
<client client_id="44">
<first_name>Barak</first_name>
<last_name>Obama</last_name>
</client>
<patient patient_id="4444" patient_species="CANINE" patient_gender="MALE_INTACT">
<patient_name>Bo</patient_name>
<patient_breed>Portuguese Water Dog</patient_breed>
<patient_birth_dt>04/04/2004</patient_birth_dt>
<patient_weight patient_weight_uom="lbs">
<weight>44.4</weight>
</patient_weight>
</patient>
<doctor>
<first_name>Surgeon</first_name>
<last_name>General</last_name>
</doctor>
<service_add>
<service_cd>ALB</service_cd>
<service_cd>GLU</service_cd>
<service_cd>BUN</service_cd>
</service_add>
</work_request>
</body>
</message>
If anyone can suggest any brilliant shortcuts as compared to the obvious solution, we would be forever grateful.
Thanks in advance.
Serializing with XmlSerializer is likely going to be the easiest solution. If classes auto-generated by xsd.exe are too bloated, you can use another code generation tool such as https://xmltocsharp.azurewebsites.net/ to generate them for you -- or even do it yourself manually.
For instance, I generated the following types using https://xmltocsharp.azurewebsites.net/ then made a few manual tweaks that are mentioned in comments:
[XmlRoot(ElementName="header")]
public class Header {
// I modified the types of these properties from string to Guid
[XmlElement(ElementName="from_application_id")]
public Guid From_application_id { get; set; }
[XmlElement(ElementName="to_application_id")]
public Guid To_application_id { get; set; }
}
[XmlRoot(ElementName="client")]
public class Client {
[XmlElement(ElementName="first_name")]
public string First_name { get; set; }
[XmlElement(ElementName="last_name")]
public string Last_name { get; set; }
[XmlAttribute(AttributeName="client_id")]
public string Client_id { get; set; }
}
[XmlRoot(ElementName="patient_weight")]
public class Patient_weight {
// I changed weight from string to decimal
[XmlElement(ElementName="weight")]
public decimal Weight { get; set; }
[XmlAttribute(AttributeName="patient_weight_uom")]
public string Patient_weight_uom { get; set; }
}
[XmlRoot(ElementName="patient")]
public class Patient {
[XmlElement(ElementName="patient_name")]
public string Patient_name { get; set; }
[XmlElement(ElementName="patient_breed")]
public string Patient_breed { get; set; }
[XmlElement(ElementName="patient_birth_dt")]
public string Patient_birth_dt { get; set; }
[XmlElement(ElementName="patient_weight")]
public Patient_weight Patient_weight { get; set; }
[XmlAttribute(AttributeName="patient_id")]
public string Patient_id { get; set; }
[XmlAttribute(AttributeName="patient_species")]
public string Patient_species { get; set; }
[XmlAttribute(AttributeName="patient_gender")]
public string Patient_gender { get; set; }
}
[XmlRoot(ElementName="doctor")]
public class Doctor {
[XmlElement(ElementName="first_name")]
public string First_name { get; set; }
[XmlElement(ElementName="last_name")]
public string Last_name { get; set; }
}
[XmlRoot(ElementName="work_request")]
public class Work_request {
[XmlElement(ElementName="client")]
public Client Client { get; set; }
[XmlElement(ElementName="patient")]
public Patient Patient { get; set; }
[XmlElement(ElementName="doctor")]
public Doctor Doctor { get; set; }
// I simplied this into a list of strings.
[XmlArray(ElementName="service_add")]
[XmlArrayItem("service_cd")]
public List<string> Service_add { get; set; }
[XmlAttribute(AttributeName="requisition_number")]
public string Requisition_number { get; set; }
}
[XmlRoot(ElementName="body")]
// I renamed this to WorkRequestBody
public class WorkRequestBody
{
[XmlElement(ElementName="work_request")]
public Work_request Work_request { get; set; }
}
[XmlRoot(ElementName="message")]
// I made this generic to account for multiple types of messge.
public class Message<T> where T : class, new()
{
[XmlElement(ElementName="header")]
public Header Header { get; set; }
[XmlElement(ElementName="body")]
public T Body { get; set; }
[XmlAttribute(AttributeName="message_id")]
public string Message_id { get; set; }
[XmlAttribute(AttributeName="message_dt")]
public string Message_dt { get; set; }
[XmlAttribute(AttributeName="message_type")]
public string Message_type { get; set; }
[XmlAttribute(AttributeName="message_sub_type")]
public string Message_sub_type { get; set; }
[XmlAttribute(AttributeName="message_dtd_version_number")]
public string Message_dtd_version_number { get; set; }
}
Using these types, I can now deserialize and re-serialize your XML into a Message<WorkRequestBody> and the resulting re-serialized XML is equivalent to the original XML, according to XNode.DeepEquals(). Sample fiddle.
To include a <!DOCTYPE ...> in the re-serialized XML, see this question.
Implementing IXmlSerializable for the root object is roughly the same difficulty as manually reading and writing your entire object graph with an XmlReader and XmlWriter. It's certainly possible but will require more work that using XmlSerializer. You'll still need to design POCOs to hold the data in memory, so it will be easier to use a serializer to read and write those POCOs automatically whenever possible. See here for a guide on how to do it correctly.
Reading and writing with LINQ to XML would represent an intermediate level of difficulty.
Finally, DataContractSerializer is not appropriate since there is no way to indicate that certain c# properties should be serialized as XML attributes (source).
Is there a way to get Automapper to map a complex source graph like:
public class Source {
public string Name { get; set; }
public SourceSub Sub { get; set; }
}
public class SourceSub {
public string ValA { get; set; }
public string ValB { get; set; }
}
to a flat destination that looks like:
public class Dest {
public string Name { get; set; }
public string ValA { get; set; }
public string ValB { get; set; }
}
I know something like this will work for a destination:
public class Dest {
public string Name { get; set; }
public string SubValA { get; set; }
public string SubValB { get; set; }
}
However, I am looking for a way to map to the destination without requiring a prefix in the destination properties (for the child class in the source) as long as the names in the child class properties of the source match the destination property names. Is there a way to tell Automapper to project properties in a child class of the source to a flat destination class without mapping each individual member?
No, this isn't a supported scenario right now. We looked at it for a while, but found the naming collision rate too high for our apps, and having the name flattened preserved the full context for where that value came from.