I have the following requirement: There are basically two classes Object and Attribute. I want to model the database in such a way that one Object can have many Attributes which is easy to do. But the othe requirement is that one Object can also have many other Objects. How would that be possible to implement and what do I need to do in my Model Classes to achieve this?
So far I have this:
public class Object
{
public int ID { get; set; }
public Attribute Attribute { get; set; }
}
public class Attribute
{
public int ID { get; set; }
public string Name { get; set; }
public string Type { get; set; }
public Object Object { get; set; }
}
I believe you can just add new property to your object class, that targets the object you want, so something like this:
public class Object
{
public int ID { get; set; }
public Attribute Attribute { get; set; }
public Object Object { get; set; }
}
public class Attribute
{
public int ID { get; set; }
public string Name { get; set; }
public string Type { get; set; }
public Object Object { get; set; }
}
but from the code provided, your Object class references just one instance of the Attribute class, so you dont have 1:N relation as you said you want, but rather 1:1! If you want the Object class to point to several Attributes and several Object Instances, the code should be something like this:
public class Object
{
public int ID { get; set; }
public Object ParentObject { get; set; }
}
public class Attribute
{
public int ID { get; set; }
public string Name { get; set; }
public string Type { get; set; }
public Object ParentObject { get; set; }
}
EDIT: https://www.entityframeworktutorial.net/code-first/configure-one-to-many-relationship-in-code-first.aspx
I guess what your looking for is Many-to-many relationships for the Database.
You could structure it like this, which will give you one extra table.
public class Object
{
public int ID { get; set; }
}
public class Attribute
{
public int ID { get; set; }
public string Name { get; set; }
public string Type { get; set; }
}
public class ObjectAndAttribute
{
public int id { get; set; }
public Attribute Attribute { get; set; }
public Object Object { get; set; }
}
Let's say I have two different classes. They share some properties, but also have some individual ones.
public class A
{
// Shared properties
public int Id { get; set; }
public DateTime CreatedDtm { get; set; }
public string CreatedBy { get; set; }
// Individual properties
public string PhoneNumber { get; set; }
public string EmailAddress { get; set; }
}
public class B
{
// Shared properties
public int Id { get; set; }
public DateTime CreatedDtm { get; set; }
public string CreatedBy { get; set; }
// Individual properties
public string StreetAddress { get; set; }
public string PostalCode{ get; set; }
public string City{ get; set; }
}
Now the trick is, that I would like to store these two types as the same entity. This is possible, if I convert the individual properties to JSON. So I could make a shared entity, like this:
public class C
{
// Shared properties
public int Id { get; set; }
public DateTime CreatedDtm { get; set; }
public string CreatedBy { get; set; }
// Individual properties
public object IndividualProperties { get; set; }
}
But if I do this, I lose all the advantages of a static typed language as well as all the benefits of polymorphism, doing this (e.g. class A might have some different validations from class B).
Isn't there some way of doing the conversion, just before saving the entity, via Entity Framework (Core)? I could of course write the mapping myself, but I got a feeling that there should be a shortcut to this...
Basically, I want to do something like this (doesn't matter if it's an interface, abstract class or something completely different):
public void AddEntity(ISomeSharedInterface entity)
{
C sharedEntity = SomeMappingMethod(entity);
db = new Context();
db.SharedEntities.Add(sharedEntity);
db.SaveChanges();
}
If you wonder about this design, it is for an automation process. The various sub-forms which needs to be filled during the process vary, but I would like to store all items in the same table.
If you create an abstract base class, this should just work without any additional configuration:
public abstract class Base
{
// Shared properties
public int Id { get; set; }
public DateTime CreatedDtm { get; set; }
public string CreatedBy { get; set; }
}
public class A : Base
{
// Individual properties
public string PhoneNumber { get; set; }
public string EmailAddress { get; set; }
}
public class B : Base
{
// Individual properties
public string StreetAddress { get; set; }
public string PostalCode{ get; set; }
public string City{ get; set; }
}
class Context : DbContext
{
DbSet<Base> Bases { get; set; }
}
public void AddEntity(Base entity)
{
using (db = new Context())
{
db.Bases.Add(entity);
db.SaveChanges();
}
}
More info here.
I have a class
public class MyClass
{
public string v1 { set; get; }
public string v2 { set; get; }
public string v3 { set; get; }
public string i1 { set; get; }
public string i2 { set; get; }
public string i3 { set; get; }
public string error { set; get; }
public string date { set; get; }
}
when i Serialize the class
MyClass meter = new MyClass();
var json = new JavaScriptSerializer().Serialize(meter);
i get
{
"v1":"2342",
"v2":"2336",
"v3":"2332",
"i1":"38.90",
"i2":"42.21",
"i3":"30.87",
"error":"",
"date":"26/02/2015 08:16:14"
}
how can i change the display name of every member (like [ScriptIgnore])
i tried [Display(Name = "myname")]
There are two ways
1) Use the Newtonsoft.Json and just add the property name to display There are this way
[JsonProperty(PropertyName = "owner")]
public string Owner { get; set; }
2) If you stick with javascriptserializer then here is the code to how to do it.
JavaScriptSerializer.Deserialize - how to change field names
I think you should use the Newtonsoft why reinvent the wheel??
I have used JSON to C# Class Converter and it generates the following Class:
JSON
{"ios_info":{"serialNumber":"F2LLMBNJFFF","imeiNumber":"01388400413235","meid":"","iccID":"8901410427640096045","firstUnbrickDate":"11\/27\/13","lastUnbrickDate":"11\/27\/13","unbricked":"true","unlocked":"false","productVersion":"7.1.2","initialActivationPolicyID":"23","initialActivationPolicyDetails":"US AT&T Puerto Rico and US Virgin Islands Activation Policy","appliedActivationPolicyID":"23","appliedActivationDetails":"US AT&T Puerto Rico and US Virgin Islands Activation Policy","nextTetherPolicyID":"23","nextTetherPolicyDetails":"US AT&T Puerto Rico and US Virgin Islands Activation Policy","macAddress":"ACFDEC6C988A","bluetoothMacAddress":"AC:FD:EC:6C:98:8B","partDescription":"IPHONE 5S SPACE GRAY 64GB-USA"},"fmi":{"#attributes":{"version":"1","deviceCount":"1"},"fmipLockStatusDevice":{"#attributes":{"serial":"F2LLMBNJFFFQ","imei":"013884004132355","isLocked":"true","isLost":"false"}}},"product_info":{"serialNumber":"F2LLMBNJFFF","warrantyStatus":"Apple Limited Warranty","coverageEndDate":"11\/25\/14","coverageStartDate":"11\/26\/13","daysRemaining":"497","estimatedPurchaseDate":"11\/26\/13","purchaseCountry":"United States","registrationDate":"11\/26\/13","imageURL":"http:\/\/service.info.apple.com\/parts\/service_parts\/na.gif","explodedViewURL":"http:\/\/service.info.apple.com\/manuals-ssol.html","manualURL":"http:\/\/service.info.apple.com\/manuals-ssol.html","productDescription":"iPhone 5S","configDescription":"IPHONE 5S GRAY 64GB GSM","slaGroupDescription":"","contractCoverageEndDate":"11\/25\/15","contractCoverageStartDate":"11\/26\/13","contractType":"C1","laborCovered":"Y","limitedWarranty":"Y","partCovered":"Y","notes":"Covered by AppleCare+ - Incidents Available","acPlusFlag":"Y","consumerLawInfo":{"serviceType":"","popMandatory":"","allowedPartType":""}}}
From Above JSON all the data is read but only the line at which i get error is in reading the JSON is:
fmi":{"#attributes":{"version":"1","deviceCount":"1"},"fmipLockStatusDevice":{"#attributes":{"serial":"F2LLMBNJFFFQ","imei":"013884004132355","isLocked":"true","isLost":"false"}}},
Error:
Object Reference not set to an instance of object.
public class AppleAPI
{
public IosInfo ios_info { get; set; }
public ProductInfo product_info { get; set; }
public Fmi fmi { get; set; }
public class IosInfo
{
public string serialNumber { get; set; }
public string imeiNumber { get; set; }
public string meid { get; set; }
public string iccID { get; set; }
public string firstUnbrickDate { get; set; }
public string lastUnbrickDate { get; set; }
public string unbricked { get; set; }
public string unlocked { get; set; }
public string productVersion { get; set; }
public string initialActivationPolicyID { get; set; }
public string initialActivationPolicyDetails { get; set; }
public string appliedActivationPolicyID { get; set; }
public string appliedActivationDetails { get; set; }
public string nextTetherPolicyID { get; set; }
public string nextTetherPolicyDetails { get; set; }
public string macAddress { get; set; }
public string bluetoothMacAddress { get; set; }
public string partDescription { get; set; }
}
public class ConsumerLawInfo
{
public string serviceType { get; set; }
public string popMandatory { get; set; }
public string allowedPartType { get; set; }
}
public class ProductInfo
{
public string serialNumber { get; set; }
public string warrantyStatus { get; set; }
public string coverageEndDate { get; set; }
public string coverageStartDate { get; set; }
public string daysRemaining { get; set; }
public string estimatedPurchaseDate { get; set; }
public string purchaseCountry { get; set; }
public string registrationDate { get; set; }
public string imageURL { get; set; }
public string explodedViewURL { get; set; }
public string manualURL { get; set; }
public string productDescription { get; set; }
public string configDescription { get; set; }
public string slaGroupDescription { get; set; }
public string contractCoverageEndDate { get; set; }
public string contractCoverageStartDate { get; set; }
public string contractType { get; set; }
public string laborCovered { get; set; }
public string limitedWarranty { get; set; }
public string partCovered { get; set; }
public string notes { get; set; }
public string acPlusFlag { get; set; }
public ConsumerLawInfo consumerLawInfo { get; set; }
}
public class Fmi
{
public Attributes invalid_nameattribute { get; set; }
public FmipLockStatusDevice fmipLockStatusDevice { get; set; }
}
public class FmipLockStatusDevice
{
public Attributes2 invalid_nameattribute2 { get; set; }
}
public class Attributes
{
public string version { get; set; }
public string deviceCount { get; set; }
}
public class Attributes2
{
public string serial { get; set; }
public string imei { get; set; }
public string isLocked { get; set; }
public string isLost { get; set; }
}
}
Reading JSON:
string responseText = string.Empty;
AppleAPI appobj = new AppleAPI();
responseText = appobj.VerifyAppleESN(newEsn);
var resobj = JsonConvert.DeserializeObject<AppleAPI>(responseText.Replace("#",string.Empty));
lblSerialNumber.Text = resobj.product_info.serialNumber;
.
.
lblappliedActivationDetails.Text = resobj.ios_info.appliedActivationDetails;
.
.
//getting here error below line: Object ref notset to instance of object
lblfmiVersion.Text = resobj.fmi.invalid_nameattribute.version;
Any Idea?
If you're getting Object Reference not set to an instance of object. that means that you're trying to access properties on an object that is null. Since you said it happens on this line:
lblfmiVersion.Text = resobj.fmi.invalid_nameattribute.version;
that could mean that any of resobj, resobj.fmi, or resobj.fmi.invalid_nameattribute are null. Ignoring the fact that you should have proper null checks in your code to help avoid this situation, let's ask the question, why would any of these objects be null if deserialization succeeded? Perhaps some of the data was not deserialized correctly after all.
When deserializing using Json.Net, it is important to know that if any members of a class do not have matching properties in the JSON, those members will be skipped by Json.Net and thus retain their default values, e.g. null. So one possible reason that you have a null is that the name of a property in your class does not match what is in the JSON.
If we take a look at your Fmi class, one thing that jumps out right away is that it has a suspiciously named property called invalid_nameattribute. In the JSON, there is no such property. Instead, there is a property called #attributes. Your FmipLockStatusDevice class has the same problem. Since they didn't match up, these properties did not get populated during deserialization, so they are null.
So how can we fix this?
This is simple enough: add a [JsonProperty] attribute to your class properties to map them to the right JSON properties. (While you're at it, you might also consider changing the names of those properties in your C# class to something that actually makes sense, like "Attributes".)
public class Fmi
{
[JsonProperty("#attributes")]
public Attributes invalid_nameattribute { get; set; }
public FmipLockStatusDevice fmipLockStatusDevice { get; set; }
}
public class FmipLockStatusDevice
{
[JsonProperty("#attributes")]
public Attributes2 invalid_nameattribute2 { get; set; }
}
OK, now that you have a solution, you should ask yourself, how did you get into this situation in the first place, and how can you avoid it in the future?
You said you used json2csharp.com to generate your classes. You need to be aware that this tool is not foolproof, and will not always be able to generate correct classes to work with your JSON. This is true whenever the JSON property names contain punctuation characters or spaces or start with numbers, because these cannot be turned into valid C# property names. In these cases, json2csharp.com will generate a property name that starts with "invalid". You need to look for these, and make manual adjustments to your classes to fix the issues. Do not just blindly use the generated classes and assume they are correct.
Hope this helps.
I am trying to understand how to create a ViewModel that contains properties from a class in my domain model as well as properties from a parent class.
I want to have a ViewModel that contains all of the LoadSession properties and the TradingPartner Description, but I'm not sure how to map this all up in the ViewModel. Any help or advice would be greatly appreciated.
This is my main class I'm accessing named LoadSession:
public partial class LoadSession
{
public LoadSession()
{
this.AcceptedTransactions = new HashSet<AcceptedTransaction>();
this.RejectedTransactions = new HashSet<RejectedTransaction>();
}
public int LoadSessionId { get; set; }
public int Import { get; set; }
public string FilePath { get; set; }
public string TradingPartnerBatchId { get; set; }
public System.DateTime Started { get; set; }
public int RecordsOnFile { get; set; }
public int RecordsAfterGroupFilter { get; set; }
public int RecordsAccepted { get; set; }
public int RecordsRejected { get; set; }
public System.DateTime Completed { get; set; }
public bool Success { get; set; }
public Nullable<int> Extract { get; set; }
public virtual ICollection<AcceptedTransaction> AcceptedTransactions { get; set; }
public virtual Extract Extract1 { get; set; }
public virtual Import Import1 { get; set; }
public virtual ICollection<RejectedTransaction> RejectedTransactions { get; set; }
}
The Import property is a foreign key for this Import class (Import = ImportId):
public partial class Import
{
public Import()
{
this.GroupPlans = new HashSet<GroupPlan>();
this.ImportGroups = new HashSet<ImportGroup>();
this.MatchingGroups = new HashSet<MatchingGroup>();
this.LoadSessions = new HashSet<LoadSession>();
}
public int ImportId { get; set; }
public string Description { get; set; }
public int Format { get; set; }
public int Interface { get; set; }
public virtual Interface Interface1 { get; set; }
public virtual Format Format1 { get; set; }
public virtual ICollection<GroupPlan> GroupPlans { get; set; }
public virtual ICollection<ImportGroup> ImportGroups { get; set; }
public virtual ICollection<MatchingGroup> MatchingGroups { get; set; }
public virtual ICollection<LoadSession> LoadSessions { get; set; }
}
The Interface property is a foreign key for this Interface class (Interface = InterfaceId):
public partial class Interface
{
public Interface()
{
this.Extracts1 = new HashSet<Extracts1>();
this.Imports = new HashSet<Import>();
}
public int InterfaceId { get; set; }
public string Description { get; set; }
public int TradingPartner { get; set; }
public virtual ICollection<Extracts1> Extracts1 { get; set; }
public virtual ICollection<Import> Imports { get; set; }
public virtual TradingPartner TradingPartner1 { get; set; }
}
And the TradingPartner property is a foreign key for this TradingPartner class (TradingPartner = TradingPartnerId):
public partial class TradingPartner
{
public TradingPartner()
{
this.Interfaces = new HashSet<Interface>();
}
public int TradingPartnerId { get; set; }
public string Description { get; set; }
public virtual ICollection<Interface> Interfaces { get; set; }
}
Well, those are all your domain objects right...
Create a repository that takes your Domain object and transforms then to into a view model with the properties you need...
I am not sure what it is your view needs, but from your statements you state that you want properties of Load session + TradingPartner.Description So create something like this...
public class LoadSessionTradingPrtNrVM
{
public LoadSession()
{
this.AcceptedTransactions = new HashSet<AcceptedTransaction>();
this.RejectedTransactions = new HashSet<RejectedTransaction>();
}
public int LoadSessionId { get; set; }
public int Import { get; set; }
public string FilePath { get; set; }
public string TradingPartnerBatchId { get; set; }
public System.DateTime Started { get; set; }
public int RecordsOnFile { get; set; }
public int RecordsAfterGroupFilter { get; set; }
public int RecordsAccepted { get; set; }
public int RecordsRejected { get; set; }
public System.DateTime Completed { get; set; }
public bool Success { get; set; }
public Nullable<int> Extract { get; set; }
public string Description { get; set; }
public virtual ICollection<AcceptedTransaction> AcceptedTransactions { get; set; }
public virtual Extract Extract1 { get; set; }
public virtual Import Import1 { get; set; }
public virtual ICollection<RejectedTransaction> RejectedTransactions { get; set; }
}
To get from Domain models to ViewModels you would use a repository, or some other pattern that takes what you get from your database and transforms it into what you need for your views.
This is kind of raw, but the theory should hold...
public class DataRepository {
LoadSessionTradingPrtNrVM TransformToVM(LoadSession inputA, TradingPartner inputB){
LoadSessionTradingPrtNrVM newOBJ = new LoadSessioNTradingPrtNrVM();
newOBJ.LoadSessionId = ipnutA.LoadSessionID;
newOBJ.Import = inputA.Import
//Here is the property from your Transform object
newOBJ.Description = inputB.Description
//... Continue to transform one object into the other...
//You could add as many members from as many different objects as you want into
//Your view model following that pattern.
}
}
I didn't have a chance to run this through a C# compiler, but you should get the general idea. I am sure there is a more elegant pattern that can accomplish the same thing. But this is a decent solution off the top of my head.
Another option is to include the domain model objects as properties in the view model. For example:
// View model.
public class UserViewModel
{
public AddressModel Address; // Assuming "AddressModel" is a doman model.
public string FirstName;
public string LastName;
}
And in the view you can access the properties as:
#Model.Address.AddressLine1
#Model.Address.City
// etc...
The Html helpers handle this just fine, but if you are manually naming inputs in your view don't forget to adjust those names to match.