I have two lists of different objects, one from a third party API and one from my database - and I'm trying to link the two as a relationship. Ideally with a similar effect of how DBML's create relationships for tables with foreign keys (Customer.Orders).
From third party:
class ApiObject {
public string ID { get; set; }
public string Title { get; set; }
public DateTime CreatedDate { get; set; }
... 30 other properties ...
}
From my database:
class DbmlObject {
public int ID { get; set; }
public string ApiID { get; set; }
public string OtherString { get; set; }
}
They are related through ApiObject.ID == DbmlObject.ApiID
I do not want to merge these, nor join them into some anonymous object (and explicitly list 30+ properties) - but rather to make the DbmlObject a linked property of ApiObject. i.e.: addressable as:
apiObject.DbmlObjects.First().OtherString or ideally apiObject.DbmlObject.OtherString since it is a 1 to 1 relationship.
In controller:
List<ApiObject> apiObjects = _thirdParty.GetObjects();
DbmlDataContext model = new DbmlDataContext();
List<DbmlObject> dbmlObjects = model.GetAllDbmlObjects();
// relate them here
foreach (var apiObject in apiObjects)
Console.Write(apiObject.DbmlObject.OtherString)
// NOTE: ideally this foreach loop should not make a DBML query on each iteration, just the single GetAllDbmlObjects query above.
It sounds like a join:
var combined = from api in apiObjects
join dbml in dbmlObjects on api.ID equals dbml.ApiID
select new { api, dbml }
In order to get DbmlObject "in" the ApiObject, you will need to either inherit ApiObject and construct a new one of that class, which includes the Dbml property, or create a entirely new class to return. If you need static typing this is the best you can do - of course you could (mis)use dynamic to get what you want.
In this case, you are mentioning (in comments) that the ApiObject class is from a third party library that you can't change - in this case I would probably choose to create a new type which takes an instance of both objects in the constructor and exposes the properties you need - a decorator. Yes, it looks like a lot of code, but it is not complex, good tools will autogenerate it for you - and you get the class that you need for your code to be succinct.
In case you want to go further with returning an IEnumerable<dynamic>, you could build a "combining dynamic" object based on DynamicObject that then responds to all the properties of ApiObject and DbmlObject - or just adds DbmlObject as a property. I am not saying this is the right way to go, it depends on what you need it for - remember you are losing type safety. Here is a simple example:
void Main()
{
dynamic dyn = new CombiningDynamic(new Foo { X = 3 }, new Bar { Y = 42 });
Console.WriteLine(dyn.X);
Console.WriteLine(dyn.Y);
}
public class Foo
{
public int X {get;set;}
}
public class Bar
{
public int Y { get;set;}
}
public class CombiningDynamic : DynamicObject
{
private object [] innerObjects;
public CombiningDynamic(params object [] innerObjects)
{
this.innerObjects = innerObjects;
}
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
foreach(var instance in innerObjects)
{
Type t = instance.GetType();
PropertyInfo prop = t.GetProperty(binder.Name);
if (prop != null && prop.CanRead)
{
result = prop.GetValue(instance, null);
return true;
}
}
result = null;
return false;
}
}
Remember, this is example code. If you really go this way, you would want to perhaps override some more of the methods (TrySetMember, ...), and you most definetely would want to cache the reflection results so you don't need to walk the types each time - reflection is (comparatively) slow.
Related
Class Person {
int Id
string Name
string Address
// etc
}
instead of accessing it like Person.Id, Person.Name, Person.Address. I want to access it via index just like Person['Id'], Person['Name']. Is there any codegen or linq conversion for this.
You can use Json.NET's JObject class
Person p = new Person() { Id = 1, Address = "A", Name = "B" };
var obj = JObject.FromObject(p);
Console.WriteLine(obj["Id"]); //1
This is a pure C# implementation:
class Program
{
static void Main(string[] args)
{
Person person = new Person
{
Id = 1,
Name = "test",
Address = "tost"
};
Console.WriteLine(person["Id"]);
person["Id"] = 5;
Console.WriteLine(person["Id"]);
}
}
public class Person
{
public int Id { get; set; }
public string Name { get; set; }
public string Address { get; set; }
public object this[string propertyName]
{
get
{
return this.GetType().GetProperty(propertyName).GetValue(this);
}
set
{
this.GetType().GetProperty(propertyName).SetValue(this, value);
}
}
}
Output:
1
5
Important note:
I would never recommend to use this in a production environment, if you want to use an handly implemented system, atleast you should handle types and properties extractions to avoid consuming more memory than needed and exceeding overheads.
Using reflection and indexers:
public class ExampleClass{
public object this[string name]
{
get
{
var properties = typeof(ExampleClass)
.GetProperties(BindingFlags.Public | BindingFlags.Instance);
foreach (var property in properties)
{
if (property.Name == name && property.CanRead)
return property.GetValue(this, null);
}
throw new ArgumentException("Can't find property");
}
set {
return;
}
}
}
An indexer won't make data comparison any easier. I suspect the real question is how to handle data in C# the same way Python's DataFrames work. ADO.NET provides the DataTable class since .NET 1.0. It's meant more for database processing than data analysis, altough it does support operations like searching, merging and diffing.
For data anlysis, the new Microsoft.Data.Analysis package provides the DataFrame class.
That said, to read properties by name, you'll have to use Reflection, an expensive operation. One way to make this cheaper is to cache type and property descriptors. Instead of writing the code yourself though, you can use Marc Gravel's FastMember library that does just that. With this, you can create a TypeAccessor or ObjectAccessor type and read properties by name, eg :
var wrapped = ObjectAccessor.Create(obj);
string propName = // something known only at runtime
Console.WriteLine(wrapped[propName]);
If you want to read from multiple objects, you'll need a TypeAccessor :
var accessor = TypeAccessor.Create(type);
string propName = // something known only at runtime
while( /* some loop of data */ )
{
accessor[obj, propName] = rowValue;
}
The library isn't that big. If you aren't allowed to use NuGet packages, you could copy the code into your project.
I was wondering if I have an object that contains a field which has its deserialization process dependant on another field, how can I deserialize the parent object?
Container
class Container
{
public int Id { get; set; }
public object Data { get; set; } //deserialization depends on first field
}
Hierarchy
class FieldType1
{
public string Value { get; set; }
}
class FieldType2
{
public int Numbers { get; set; }
}
Given the example above if I have a Dictionary<int,Type> how can I deserialize an object that comes as a string like the one below?:
var container = new Container { Data = new FieldType1 { Value = "sata" }};
var str = JsonConvert.SerializeObject(container);
var clone = JsonConvert.DeserializeObject<Container>(str);//has dependant field on another field
As you can see in my example above I always have the same container type.but one property differs.
Update
After some answers here could it be possible to keep only one type of parent object and instead have a base type for the second field ?
[JsonSubTypes.KnownSubType(typeof(Child1),1)]
[JsonSubTypes.KnownSubType(typeof(Child2),2)]
public abstract Child
{
}
public class Parent{
public int Id;
public Child child;
}
Can i decorate somehow the parent to know how to deserialize its second field (similar to JsonSubTypes)?
Summing it up i do not want to have P,P1,P2..Pn types for parent.
I want to have one type P for parent with F1,F2...Fn types for its second field.So that when i deserialize i would just say JsonConvert.DeserializeObject<P> while the converter takes care of which concrete type is the second field:
Parent c1=new P{ id=1,child=new Child1()};
Parent c2=new P{ id=2,child=newChild2()};
List<Parent> items=new List<Parent>{c1,c2};
var str=JsonConvert.SerializeObject(items);
var clone=JsonConvert.DeserializeObject<List<Parent>>(str);
At a first glance, I'd simply use a simple function that you could put into a SomeNameParser/Converter class.
Pesudo C# code, something like the following:
var jObject = JObject.Parse(obj.Data);
switch (jObject["firstField"])
{
case "fieldType1":
return JsonConvert.DeserializeObject<string>(str);
case "fieldType2":
return JsonConvert.DeserializeObject<int>(str);
default:
Throw new Exception( make this meaningful)
}
Improvements
You could make the parsing of the firstField do a lookup to return a System.Type, then pass the type to JsonConvert.Deserialize(obj.Data, type) which would save the repetitive JsonConvert.
Hopefully you can see the general pattern.
I am working on a ASP.NET MVC project, with C#, and EF code first.
I am required to add dynamic properties to entities. For example -
I have a car as a base object. I can add custom properties for it like engine power, length, color etc etc.
Properties can be boolean, int, string or select options (ie, i have to create checkbox, input or select html elements when a user inputs values for those properties).
Properties must have custom validation rules (i.e., required, number only, range only etc).
Can you guys give me any clues or direction how to accomplish this?
Thank you
If you truly have dynamic properties you won't be able to do this (directly) with EF6 since EF6 assumes a relation database. and a relational database needs to know which columns to expect.
Now you got 2 options.
Option1:
use a non-relational database with EF 7. you can look here https://msdn.microsoft.com/en-us/magazine/dn890367.aspx for some more details about EF7 but basically in a non relation database you can store any json blob - so also your dynamic properties
Option 2: Use a key value pair within your object. and store those properties
class KeyValuePair {
int Id {get; set;}
string name {get; set;}
string stringValue {get; set;}
}
class BaseObject {
int Id {get; set;}
list<KeyValuePair> dynamicProperties {get; set;}
}
Now your car can just inherit from this baseobject. You still need to do the work to create your KeyValuePair objects. (And if you want to store strings, ints etc you can make Different KeyValuePair types, one for each storage type)
Be carefull with performance though if you use dynamic properties like this.
Update:
If you want to validate a dynamic object like this you want to implement IValidatableObject
so you get
class Car: BaseObject, IValidatableObject {
public virtual IEnumerable<ValidationResult> Validate(ValidationContext validationContext) {
/* code to validate your properties here, for example you need at least 1 engine, 4 wheels etc */
yield return ValidationResult.Success;
}
}
You can create and use tables in DB dynamically, although it's not so simply.
First, you'll need to store metadata about your tables — what are their names, what are properties they have, what are the types of those properties, and so on.
Second, you'll need to generate entities to access these tables, and also, EntityTypeConfiguration classes, like here:
public class Foo
{
public int Id { get; set; }
public string Name { get; set; }
}
public class FooTypeConfiguration : EntityTypeConfiguration<Foo>
{
public FooTypeConfiguration()
{
ToTable("Foos");
HasKey(t => t.Id);
Property(t => t.Name).HasMaxLength(200)
.IsRequired();
}
}
You can generate DLL dynamically without intermediate C# code with help of System.Reflection.Emit. Or you can generate C# code and use System.CodeDom.Compiler to compile it (this way is simpler). You can also try Roslyn compiler (but I don't have enough experience to advise it).
Third, you'll need to load compiled DLL and create DbContext using modelBuilder.Configurations.AddFromAssembly(...).
You can find required type in assembly and use it to access data:
string typeName = ...;
var type = dynamicLoadedAssembly.GetType(typeName);
var set = dbContext.Set(type); // non-generic DB Set
You can use System.Reflection or dynamic typing to work with these objects.
Finally, if you'll generate C# code, you can generate properties and implementation of some interface to access these properties by names:
public interface IAccessorByName : IReadOnlyDictionary<string, object>
{
object this[string name] { get; set; }
}
public Foo : IAccessorByName
{
private static readonly IDictionary<string, Func<Foo, object>> getters = new Dictionary<string, Func<Foo, object>>
{
{ "Id", (foo) => foo.Id },
{ "Name", (foo) => foo.Name },
};
private static readonly IDictionary<string, Action<Foo, object>> setters = new Dictionary<string, Action<Foo, object>>
{
{ "Id", (foo, value) => { foo.Id = (int)value; } },
{ "Name", (foo, value) => { foo.Name = (string)value; } },
};
public int Id { get; set; }
public string Name { get; set; }
public object this[string name]
{
get { return getters[name](this); }
set { setters[name](this, value); }
}
}
With similar interface you can create, read, update, and delete objects dynamically:
string typeName = "Foo";
var fooType = dynamicLoadedAssembly.GetType(typeName);
var foo = (IAccessorByName)Activator.CreateInstance(fooType);
foo["Id"] = 1;
foo["Name"] = "Jon Skeet";
var fooSet = dbContext.Set(fooType);
fooSet.Add(foo);
dbContext.SaveChanges();
I've 3 different database tables that have the same 5 fields but those does not have any foreign key relation as they are not keeping the same value in fact, but the equivalents; like: CompanyA table has productA and CompanyB has productB.
so I have 3 different collections include 3 fields that are equivalent. So what I'd like to do is to use a single class that has companyType and ProductName properties and use only one method to cast those 3 different collections to one and only class object, say ResultClass.
public class ResultClass
{
public EnumCompanyType CompanyType { get; set; }
public string ProductName { get; set; }
public ICollection<ResultClass> ConvertAnything(ICollection<T> collection)
{
//Cast it to ResultClass
return resultClassCollection;
}
}
So that I can use this like:
ICollection<ProductA> aCollection = GetCompanyAData();
ICollection<ProductB> bCollection = GetCompanyBData();
ConvertAnything(aCollection);
ConvertAnything(bCollection);
I've tried "dynamic" but actually don't know the principle (neither have the knowledge); so I've messed it up and I think it's not for this stuff.
I've tried to create an extension method but since the extension has no type for its parameter (as it is using ICollection), I can't access the fields of the items (eg. properties)
I'm using LinqToSql and all the database table terms etc. belongs to this concept, nothing else.
edit:
I think I should made myself clear:
The multiple instances that I'm trying to avoid (or shouldn't I, still thinking) is like below
public ICollection<ResultClass> ConvertAnythingForA(ICollection<ProductA> collection)
{
foreach(var item in collection)
{
var result = new ResultClass
{
ProductName = item.ProductA,
ProductType = EnumProductType.ProductA
};
resultClassCollection.Add(result);
}
return resultClassCollection;
}
public ICollection<ResultClass> ConvertAnythingForB(ICollection<ProductB> collection)
{
foreach(var item in collection)
{
var result = new ResultClass
{
ProductName = item.ProductB,
ProductType = EnumProductType.ProductB
};
resultClassCollection.Add(result);
}
return resultClassCollection;
}
Thanks in advance.
I may not be understanding you completely, but since ProductA, ProductB etc have the same signature it seems like you'd want an interface like
public interface IResultClass
{
int CompanyType { get; set; }
string ProductName { get; set; }
}
And have those classes just implement the interface. You could work with collections of the interface that could have objects of the various types. If you need a convert anything method, it would look like
public ICollection<IResultClass> ConvertAnything<T>(ICollection<T> collection) where T : IResultClass
{
return collection.Select(x => (IResultClass)x).ToList();
}
After comments- I see you that you are getting a non generic ICollection. Did you try something like this:
public ICollection<IResultClass> ConvertAnything(ICollection collection)
{
var x = collection.Cast<IResultClass>();
return x.ToList();
}
You may want to use function overloading. This example uses different numbers of parameters, but you could just as easily use different types instead.
http://csharp.net-tutorials.com/classes/method-overloading/
If both datasets are equivalent, why not just have one type called ICollection<Product>? And one function, eg. "GetProductData("A")", where "A"/"B" is the parameter? Or am I missing something?
I have the following business objects:
public abstract class Product
{
public int Id { get; set; }
public bool OnStock { get; set; }
}
public class ProductForImport : Product
{
public int ImportId { get; set; }
}
public class ProductForExport : Product
{
public int ExportId { get; set; }
public bool IsExportable { get; set; }
public bool IsUsable { get; set; }
public string OtherParam {get; set;}
public static implicit operator ProductForExport(ProductForImport pfi)
{
ProductForExport p = new ProductForExport();
p.Id = pfi.Id;
p.IsExportable = true;
p.ExportId = 0;
return p;
}
}
so I can convert between the two types:
static void Main(string[] args)
{
ProductForExport pfe = new ProductForExport();
pfe.Id = 1;
pfe.OnStock = true;
ProductForImport pfi = new ProductForImport();
pfi.ImportId = 200;
ProductForExport pfe2 = (ProductForExport)pfi;
}
this works OK.
I have 100.000 ProductsForImport items.
If I understand correctly, if I convert them to ProductsForExport items, I'll have 100.000 +100.000 items in memory - that's reasonable.
My problem is: I have to send these "ProductForExport" objects through JSON services, each service just need some subset of the properties of each type:
servicecall1 should return ProductForExport1{ExportId,IsExportable}
servicecall2 should return ProductForExport2{ExportId,IsUsable}
Question: should I write an implicit conversion similar to the above example for these new types - ProductForExport1 and ProductForExport2 (so basically create 100.000+100.000 new objects)
or
somehow can I just "hide" the unwanted properties with some magic from the original type without the need to create new instances?
thanks,
b.
If you ned such kind of decoupling and separation of entities - you can create DTO object along with each business object and use DTO to communicate with Service.
But if you have a lot of business entities consider an other approach to avoid maintenance hell.
public sealed class ExportProductDto
{
public(ProductForExport exportProduct)
{
// initialize fields
this.ExportId = exportProduct.ExportId;
}
public int ExportId { get; private set; }
}
BTW,
An overkill solution with operator overload, use Adapter pattern to convert between product types
To decouple adapting from entities itself implement following interface your self:
public interface IProductAdapter<TImport, TExport>
{
TImport ToImportProduct(TExport exportProduct);
TExport ToExportProduct(TImport importProduct);
}
Or an other adapter approach:
// Implement this interface for ProductForImport class
// public class ProductForImport : IExportProductAdapter, Product
public interface IExportProductAdapter
{
ProductForExport ToExportProduct();
}
// Implement this interface for ProductForExport class
// public class ProductForExport : IImportProductAdapter, Product
public interface IImportProductAdapter
{
ProductForImport ToImportProduct();
}
EDIT: Answer to comments
// An example of IExportProductAdapter adapter implementation
public sealed class ProductForImport : Product, IExportProductAdapter
{
public int ImportId { get; set; }
public ProductForExport ToExportProduct()
{
ProductForExport p = new ProductForExport();
p.Id = this.Id;
p.IsExportable = true;
p.ExportId = 0;
return p;
}
}
And then instead of:
ProductForExport pfe2 = (ProductForExport)pfi;
You can do:
ProductForExport pfe2 = pfi.ToExportProduct();
I would create light objects specifically for returning through the service with only the required fields. Then use Automapper or something like that to map them.
I don't recommend using operator overloading if you can avoid it. I have seen many issues where a developer didn't realize when the operator overload was being called and something unexpected happened.
If you are using WCF, you can apply the IgnoreDataMemberAttribute to properties you wish not to serialize.
Have a look at the ScriptIgnoreAttribute to exclude properties from json serialization.
It took me a few reads but I don't think your problem is about implicit conversion as much as how to send data via json right?
If you have your object collections of Import or Export object you can use the JavaScriptSerilizer and some anonymous types to slice and dice what data you send.
You can use Linq to select specific properties of your object in a collection, and define an anonymous type "on-the-fly" to serialize out as a json string like this:
List<ProductForExport> exportList; //the list to export
JavaScriptSerializer jss = new JavaScriptSerializer();
string output = string.Empty;
output = jss.Serialize(new
{
isExportable = True, //static named properties
iTotalProducts = exportList.Count, //dynamic values
productDataArray = exportList //all data in an array object
});
//Or build the result using just a few properties of the collection:
foreach (ExportProduct exProd in exportList)
{
output += jss.Serialize(new
{
exProd.IsExportable,
exProd.ExportID
});
}