Do I need to duplicate my Entity Framework classes in Typescript when using Angular 2? - entity-framework

Let's say I have a nice C# backend with Entity Framework. I've got my database set up and a simple class like
public class MyItem
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int ItemID { get; set; }
public string ItemName { get; set; }
}
I've got a nice Angular2 front end where I retrieve data from an API and present such as...
template: '<div>{{ItemName}} - {{ItemID}}</div>'
At the moment I have a duplicate, seemingly redundant typescript class ie
export class MyItem{
ItemID: number;
ItemName: string;
}
Is there any way I can avoid this typescript class? Can I bind to an object that isn't defined in advance? In Angular 1 we could bind to any property on the scope
{{MyItem.SomeProperty}}

In my project I've used TypeLite.
It can generate TypeScript interfaces based on your C# classes. Worked just fine. If you change smth on you backend you'll see errors in your client code without running you app.
If you don't need type safety on the client side, you can use any as was said already.
E.g.
Next C# class:
public class Person {
public string Name { get; set; }
public List<address> Addresses { get; set; }
}
will be converted to
interface Person {
Name: string;
Addresses: Address[];
}
Also you can use next tools/extensions:
TypescriptSyntaxPaste
TypeWriter - one more powerfull extension for VS.

The TypeScript class/model isn't mandatory.
You can load your HTTP data into a variable and access it like any other object with properties and arrays. e.g. data.propertyname or data.arrayname[0].propertyname.
In Angular2 you can use the HTTP service and return data which can then be converted into a JSON object using data.json()
Here is an example:
import { Http } from '#angular/http';
...
constructor(private http: Http) {
{
this.http.get(url).subscribe(
data => {
var json = data.json();
console.log(json.propertyName);
}
);
}

you can certainly get data in an any object, However you will loose out on all the Type related feature supported by Typescript.

Related

C# Serialization in MongoDb - _id on nested type, and some properties with private setters

I'm in a position where I need to serialize some complex documents into MongoDb, but I can't change the class definition as I don't have control over the source.
However, we need to ensure that callers can still use Linq, so we need to map the class correclty into MongoDb.
Current there are few issues we're faced with:
The _id_ representation is on a nested class.
There are properties with private setters that need to be serialized/ deserialzied.
The shape of the class looks a little like this:
public class AggregateType : AggregateBase
{
public int IntProperty { get; private set; }
public ComplexObject ComplexObjectProperty { get; private set; }
}
With AggregateBase looking like this:
abstract public class AggregateBase
{
public AggregateDetails Details { get; set; }
}
And finally:
public class AggregateDetails
{
public Guid Id { get; set; }
...other properties
}
On the base class AggregateBase, there is a property called Details which contains the Id of the aggregate, which is a Guid. This Id field needs to be mapped to the ObjectId or _id field within a MongoDb document.
I need to be able to serialize the document, forcing the use of the Details.Id as the _id, and have the private setters serialized too.
I've done this with CosmoDb using a custom JsonContractResolver without issue. But the move to MongoDb has proved a little more complex.
It's worth noting that there are many AggregateType classes, all with a different shape. I'd like to find a generic way of serializing them, without having to write lots of specific mappers if possible - much like we do with CosmoDb.
On top of that, we would need this solution to work with the Linq query provider for MongoDb too.
Ive thought a little about this , the only way I can see this working is if you create matching types that will serve as your POCO for inserting into mongodb. Im going to assume you are using the C# Driver for Mongo.
public class AggregateTypeDocument : AggregateBaseDocument
{
public int IntProperty { get; private set; }
public ComplexObject ComplexObjectProperty { get; private set; }
}
abstract public class AggregateBaseDocument
{
public AggregateDetailsDocument Details { get; private set; }
}
public class AggregateDetailsDocument
{
[BsonId]
public Guid Id { get; private set; }
...other properties
}
You will end up replicating the structure but just be appending Document at the end for this example. By no means do you have to conform to this
Now you can mold your types to be more mongo friendly using various attributes.
The next step would be to either in your repository ( or wherever ) to map the types with class definitions you don't have access to to your new mongo friendly ones.
I would suggest AutoMapper for this or plain old instantiation. Now you should be able to safely operate on the collection. See below example for automapper.
var normalAggregateType = new AggregateType();
var client = new MongoClient("yourconnectionstring");
var db = client.GetDatabase("mydatabase");
var collection = db.GetCollection<AggregateTypeDocument>("myaggregatetypes");
var mongoAggregateType = Mapper.Map<AggregateTypeDocument>(normalAggregateType);
collection.InsertOne(mongoAggregateType);

How to ignore properties marked with [IgnoreDataMember] when calling REST service

I am consuming a REST Xml service.
I have all the necessary classes to do this, (supplied by the dev who wrote the service) but at my end I have to save some of the responses to the DB to perform the tasks of the app I am writing.
So I have marked some of these classes I need to put in the DB as partial and extended them so that I can inherit from a DbEntity class which specifies an ID property so I can use EF to save them to the DB thus:
public interface IDbEntity
{
int ID { get; set; }
}
[Serializable]
public class DbEntity : IDbEntity
{
[IgnoreDataMember]
[XmlIgnore]
public int ID { get; set; }
}
the problem I am facing now, is that when the service call is being de-serialized I get the error
Error in line 1 position 113. 'Element' 'ElementName' from namespace '' is not expected. Expecting element '_x003C_ID_x003E_k__BackingField'
I am simply making the call like this:
var response = await client.PostAsXmlAsync<TReq>("Some/API/Call", req);
TResp val = await msg.Content.ReadAsAsync<TResp>(response)
all the properties in the original classes have Orders specified with their DataMember attributes and I have clearly marked my DB properties to be Ignored, but to no avail.
is there any way I can get this to work? - ie getting the DataContractSerializer to actually ignore the properties I have marked to be ignored when de-serializing?
as an aside, these ignored properties are also being passed to the service when making a call - does IgnoreDataMember actually do anything?
seems that the way to do this is like this
public interface IDbEntity
{
int ID { get; set; }
}
[Serializable]
[DataContract]
public class DbEntity : IDbEntity
{
[XmlIgnore]
public int ID { get; set; }
}
so basically adding the DataContract Attribute but omitting the DataMember attribute on the item you don't want
don't know how I missed that first time around. seems its opt in rather than opt out in this instance.

MVC4 and Entity Framework Inheritance and Include

I have some simple objects
public class DataClass
{
public int id;
public string Data;
}
public class Job()
{
public int id;
}
public class NewJob : Job
{
public DateTime StartDate;
public DataClass data;
}
I have then defined them in my dBContext()
public DbSet<Job> Jobs { get; set; }
public DbSet<DataClass> DataClass { get; set; }
Now if I use the following code
NewJob job = (NewJob) db.Jobs.Find(id);
This works fine but returns "data" as null
I know I define the class with the virtual keyword and it works and populates the "data" object.
public class NewJob : Job
{
public DateTime StartDate;
public virtual DataClass data;
}
But in my case I "normally" do not want the "data" object to be populated. So I need to load it on demand.
If I try something like
NewJob job = (NewJob)db.Jobs.Include("data").First();
I get an exception
A specified Include path is not valid. The EntityType 'Models.Job' does not declare a navigation property with the name 'data'.
I guess this is because it is looking at "job" and not "NewJob" when it is trying to do the include.
I also do not like the include with a string - no design time checking.
It looks like you are trying to convert data object to your domain object via type casting which is a very bad idea. What you want to do is grab your data object, instantiate your domain object, and map your data values to the domain object using some type of helper class. A very helpful tool I have been using is Automapper. Its a tool that will allow you to map one object to another. It also allows the use of regular expression to help with the mappings if the naming conventions between the 2 objects are different.
If you're using Entity Framework Code First and want to create instances of derived classes/entities you should do the following:
using (var db = new MyDbContext())
{
var newJob = db.Jobs.Create<NewJob>();
newJob.data.Data = "some data for a new job"; // this is string Data from DataClass
db.Jobs.Add(newJob);
db.SaveChanges();
}
After a lot of searching I found the following which can help.
If you include the System.Data.Entity namespace in your using clause then you can use the extension method .Include() after OfType<>() which is not normally available.
Slightly different code sample
using System.Data.Entity;
NewJob job = (NewJob)db.Jobs.OfType<NewJob>().Include(m => m.data).Where(x => x.id == id).FirstOrDefault();
This seems to be working for me in the example I used.

How to get EF POCOs from System.Data.Entities.DynamicProxies

My question is the same as this one
However, I don't really see a solution there. Lets say I have a simple model with two POCOs, Country and State.
public class Country
{
public string Code { get; set; }
public string Name { get; set; }
}
public class State
{
public string Code { get; set; }
public string Name { get; set; }
public virtual Country Country { get; set; }
}
When I use the repository to .GetStateByCode(myCode), it retrieves a dynamic proxy object. I want to send that over the wire using a WCF service to my client. The dynamic proxy is not a know type so it fails.
Here are my alternatives. I can set ProxyCreationEnabled to false on the context and then my .GetStateByCode(myCode) gives me a POCO which is great. However, the navigation property in the POCO to Country is then NULL (not great).
Should I new up a state POCO and manually populate and return that from the dynamic proxy that is returned from the repository? Should I try to use AutoMapper to map the dynamic proxy objects to POCOs? Is there something I'm totally missing here?
I think the answer from Ladislav Mrnka is clear. The Warnings Still apply. Even with this idea below. Becareful what gets picked Up. He just didnt include , if you want to proceed how to easily get data from Object a to object B. That is question at hand really.
Sample solution
See nuget package ValueInjecter (not the only tool that can do this... but very easy to use)
it allows easy copying of One object to another especially with the same properties and types.
( remember the lazy loading / navigation implications).
So vanilla option is :
var PocoObject = new Poco();
PocoObject.InjectFrom(DynamicProxy); // copy contents of DynamicProxy to PocoObject
but check the default behaviour and consider a custom rule
var PocoObject = new Poco();
PocoObject.InjectFrom<CopyRule>(DynamicProxy);
public class CopyRule : ConventionInjection
{
protected override bool Match(ConventionInfo c)
{
bool usePropertry; // return if the property it be included in inject process
usePropertry = c.SourceProp.Name == "Id"; // just an example
//or
// usePropertry = c.SourceProp.Type... == "???"
return usePropertry;
}
}

Asp.Net Mvc templated helpers with interface types

I would like to use the Asp.net MVC templated helpers functionality to generate a standard UI for my objects throughout my application, but I've run into a significant issue:
I do not directly pass class types from my controllers into their views. Instead, I pass interface types.. with the actual implementation of the Model wrapped up in a Mongo or NHibernate specific class in an indirectly referenced project.
For discussion, my objects look like:
public interface IProductRepository {
IProduct GetByName(string name);
}
public interface IProduct {
string Name { get; set; }
}
public class NHibernateProductRepository : IProductRepository {
public IProduct GetByName(string name) {
/* NHibernate Magic here */
return nhibernateFoundProduct;
}
}
public class NHibernateProduct : IProduct {
public virtual Name { get; set; }
}
public class ProductController : Controller {
public ProductController(IProductRepository productRepo) {
_ProductRepo = productRepo;
}
public ActionResult Index(string name) {
IProduct product = _ProductRepo.GetByName(name);
return View(product);
}
}
Is it possible to use interface types with the Editor.For() syntax? Are there any problems or sticking points that I need to be aware of?
I have an EditorTemplate\IProduct.ascx file available. At this time, I can't seem to get that template to be rendered without hardcoding the "IProduct" name into the Editor.For() call. I would prefer this type of 'Convention over Configuration'....
The templates helpers will use the runtime type of the object for the name. In this case you should name the file NHibernateProduct.ascx
If you don't know the name of the type at design time than you could write a helper method that would inspect the object instance and walk the list of interfaces that a particular type is implementing and return a name based on that. Then you would call the appropriate override to EditorFor that takes the string "templateName" parameter.
I have decided to use an approach with a ViewModel native to the Web project that implements the IProduct interface.