Entity Framework call best way to call a another api - entity-framework-6

Building an api around a db and as part of this we'll be calling another api and joining data in that api to the database for viewing but not storing the data in the current database. My question is if this.
In my data model I have
public class server
{
public Int32 ServerID {get;set;}
public string ServerName {get;set;}
...
}
If I add api columns with to the server object
public string ServerMemory
That of course returns and invalid column name because this is data from the api that is not in the database table.
I see a few options
Create a view within the database structure which has some blank columns and reference that within my data model.
Create another object within my data model and then reference it using virtual using something like the method mentioned here: https://jeremiahflaga.github.io/2020/02/16/entity-framework-6-error-invalid-column-name-_id/
Create another object and a cast to cast the Server object to this other object.
Is there another simpler way to reference a foreign field within an object in a data model?
Thank you.

I found this so anyone else who needs to add a column to a datamodel that does not exist in the database
using System.ComponentModel.DataAnnotations.Schema;
then you can use this:
[NotMapped]
public virtual string RoleDesc { get; set; }
Still curious if this is the best way. I guess that really revolves around your goals.

Related

OData Containment

I just learn that with the [Contained] attribute I can define a contained collection. This means the collection is no more accessible from my root oData system. Ok fine, but here is my model:
I have a user that have addresses
The user has invoices
Each invoice can have one or two addresses from the user.
On which collection should I add the contained attribute?
The answer to this completely depends on your domain model. The advice I would give is to use OData containment sparingly. It really only makes sense to use it if the entity you are marking as being a contained entity cannot exist outside of the context of the parent entity. Because of this constraint I think the use cases for OData containment are few and far in between. The advantage over a separate controller is that it can make more sense from an architectural standpoint. However your controllers become more bloated and it is more work to maintain the ODataRouteAttributes on your methods. Something which is not necessary when using convention based routing.
The example on the guide to set up OData containment explains it somewhat. It falls a bit short on why you would use it. Note that the PaymentInstrument entity has no foreign key to Account. This means that there is no separate table where the PaymentInstrument information is stored. Instead it is stored directly on the Account record. Yet is still defined as a Collection<T> so it is probably stored as JSON or across multiple columns. This might not necessarily be the case, but from a code standpoint the database could look like that.
To further explain OData containment let's say we have the domain model below.
public class HttpRequest
{
public int Id { get; set; }
public DateTime CreatedOn { get; set; }
public string CreatedBy { get; set; }
public virtual HttpResponse HttpResponse { get; set; }
}
public class HttpResponse
{
public string Content { get; set; }
public DateTime CreatedOn { get; set; }
}
As you can see the HttpResponse class has no navigation property to HttpRequest. Therefore it makes no sense to want to call GET odata/HttpResponses as we would be getting all HttpResponses, but not the HttpRequest they are linked to. In other words the HttpResponse class is useless without the context i.e. the HttpRequest for which it was produced.
The HttpResponse class not having any meaning outside of the HttpRequest context makes it a perfect candidate for OData containment. Both classes could even be saved on the same record in the database. And because it's not possible to perform a GET/POST/PUT/DELETE without specifying the id of the HttpRequest to which the HttpResponse belongs, it makes no sense for the HttpResponse class to have its own controller.
Now, back to your use case. I can see two likely domain models.
The entities User, UserAddress, Invoice and InvoiceAddress.
In this first option every single entity has their own designated address entity. OData containment would make sense here using such a design as the address entities do not exist outside of their respective parent entity. A UserAddress is always linked to a User and an InvoiceAddress is always linked to an Invoice. Getting a single UserAddress entity makes less sense because using this domain model one shouldn't care where the single address is. Instead the focus lays more on what the persisted addresses for this single User are. It's also not possible to create a UserAddress without specifying an existing User. The UserAddress entity relies on the User entity entirely.
The entities User, Invoice, TypedAddress and Address.
In this second option the Address entity is stand-alone. It exists separately from the other entities. Since an address boils down to a unique location on this planet it is only saved once. Other entities then link to the Address entity via the TypedAddress entity where they specify what kind of address it is in relation to the entity linking to it. Getting a single Address makes perfect sense using this domain model. An addressbook of the entire company could easily be retrieved by requesting GET odata/Addresses. This is where OData containment does not make sense.
Do note that it is possible to use the ODataConventionModelBuilder to configure containment. Because you do not need to add the ContainedAttribute to your class, this has the advantage of not polluting your data layer with a reference to the OData library. I would recommend this approach. In your situation I would expect to have the configuration below.
var modelBuilder = new ODataConventionModelBuilder();
modelBuilder
.EntityType<User>()
.ContainsMany(user => user.UserAddresses);
modelBuilder
.EntityType<Invoice>()
.ContainsMany(invoice => invoice.InvoiceAddresses);

.SaveChanges() stores duplicates in entity framework

for ( int i = 0; i < libraryList.Count; i++)
{
if (ModelState.IsValid)
{
context.Library.Add(libraryList[i]);
context.SaveChanges();
}
}
A library contains an entity 'predefinedgoals' which is already set up in the DB. So when the above code runs it stores dublicates of 'predefinedgoals' and assigns new ID's to them.
I read that I should attach the existing entity to the context but I'm not sure how to to do it in my scenario. The classes look like this:
class library
int libraryID
list<book> bks
.
class book
int bookID
list<importantdates> impdts
.
class importantdate
int importantdateID
predefinedgoal predfg
int numberofresellers
.
class predefinedgoal
int predefinedgoalID
string description
int daysfrompublication
I tried something like this right after ModelState.IsValid but I sense I'm doing it wrong:
var prdfgs= context.predefinedgoals.ToList();
foreach(var pg in prdfgs)
context.predefinedgoals.Attach(pg);
This answer is going to be based on a couple of assumptions, but I've seen this exact problem so many times that this is automatically my go-to answer.
What I think you're doing is that you're creating Library, Book, and ImportantDate objects (and setting up all of the relationships between them as well). In the process of doing all of this, however, you are trying to set the PreDefinedGoal navigational property on those ImportantDate objects, all the while leaving the actual int FK property (that would be something like PreDefinedGoalID), still set to 0. When that happens, Entity Framework disregards the fact that the object contained in the navigational property has an ID on it, and assumes that you are trying to create this PreDefinedGoal object from scratch, just like you're creating the ImportantDate object (as well as the others). It will then create a PreDefinedGoal object with the exact same data as the one you're actually trying to use, but it will create it as a separate, duplicate record in the database.
The solution to your problem then is simple: Don't set the navigational property. Just simply set the FK (ImportantDate.PreDefinedGoalID) to the ID of the PreDefinedGoal object that you want to hook up to it. When you do that, and you save it, Entity Framework will then reach out to the database for the correct object based on that ID, and thus you will avoid having duplicate PreDefinedGoal objects in your database.
FYI: I learned this from one of Julie Lerman's MSDN posts. If you're going to be working with EF, I highly recommend reading her posts and columns.
I am in the same situation and found a workaround. The way this workaround works makes me think that in this case EF is to blame for handling the situation badly.
In order to simplify the example I will just post an example with one object and it's navigational property.
public class Topic
{
int Id { get; set; }
public String Name { get; set; }
public String Description { get; set; }
}
public class Course
{
int Id { get; set; }
public Topic Topic { get; set; }
// additional properties don't matter now
}
Note the absence of any foreign key or other data annotations. EF6 will correctly create the database schema from this and infer that Id is the primary key.
Without workaround adding a new course for an existing topic will create a new topic object with a new Id (overwriting the Id it was given!) :
db.Courses.Add(course);
await db.SaveChangesAsync();
The braindead workaround:
course.topic = db.Topics.Find(course.topic.Id);
db.Courses.Add(course);
await db.SaveChangesAsync();
In other words, if the topic has been loaded from the context directly, EF will recognize it as an existing topic and don't try to add it again.
Update: To just attach the entity without reloading it:
db.Topics.Attach(course.topic);
However you will run into more issues with this setup, it is probably best to use ForeignKey attribute(s) and include the TopicId in Course object. Following works OK but still looks ridiculous to me:
[ForeignKey("Topic")]
public int TopicId { get; set; }
[ForeignKey("TopicId")]
public virtual Topic Topic { get; set; }
Would love to hear about a less redundant solution though.
The answer to why it stored duplicates in my scenario was that I performed tasks in two different classes - using different database context variables in each of them.
So class #1 is the one in my question, that's where I'm saving to the DB using context #1. In class #2 I retrieved all the PredefinedGoals and added them to ImportantDates but to do this I created context #2. The ID's and objects were the same but retrieved from different context variables.
I solved it by retrieving the PredefinedGoals in class #1 with context variable #1 and sent them as an argument to class #2.

Entity framework 4 code first, use the same model to multiple tables?

Im using Entity Framework 4 with code first. I have a model and i want to be able to map this model to a different table in the database based on a configuration file.
Example model:
public class Statistic
{
[Key]
public int id { get; set; }
public string jobName { get; set; }
public DateTime date { get; set; }
public int pages { get; set; }
}
Each customer has a configuration file where the table name that should be used is specified. So each customer should then have its own table (in the same database) with the model above.
How can i do this with Entity Framework 4?
I tried this in my DbContext:
modelBuilder.Entity<Statistic>().ToTable(tabelName);
But what EF does when i use this is to change the existing table name to the new tableName, not creating and using a new one.
Thanks!
It is not possible. Each class can be mapped only once per mapping set (per context in common cases). Why? Because the access point to database is a DbSet (or ObjectSet in ObjectContext API) and it is simply created this way:
var set = dbContext.Set<Statistics>();
How should EF know which mapping of Statistics class should be used? It must know which mapping to use to query correct table and to save changes to correct table. You can probably argue that it could be defined as parameter but that would expose mapping details outside to upper layer - that is undesirable.
Edit:
If your application logic never needs access to more than one customer's statistics you can create mapping per customer dynamically. You need:
Create instance of DbModelBuilder and define mapping (or fill Configurations) - in this step you will provide the name of the table for current customer
Call Build method to get DbModel instance
Call Compile on DbModel instance to get DbCompiledModel instance
Cache compiled model somewhere. Model compilation is expensive operation and you need to do it only once per each customer (and per each application restart).
Pass compiled model to DbContext constructor and use that context instance to access data only for that customer
If you need to simultaneously access data for multiple customers you must do it through SQL.

Entity Framework 4.1 - Code First with existing Database, how to define classes, using Attributes or EntityTypeConfiguration? What is the difference?

I have been studying the EF for a short time and cant find the answer to this question.
I have existing database and I am using CodeFirst to create classes for the model.
What is the difference in using Attributes and EntityTypeConfiguration to define parameters of table columns?
Since the database already has defined foreign keys and unique constraints, and so on, how and where to implement the validation for a best and most fluid result for use in ASP.NET MVC3?
Is it better to implement Attributes and CustomValidation or to use TryCatch blocks to catch errors from db?
Does Validator.TryValidateObject(myModelObject, context, results, true); use validation rules defined only as Attributes or can it use rules defined in EntityTypeConfiguration?
Thank You
Get the Entity Framework Power Tools CTP1 and it will reverse engineer your database and create entities, and a full data mapping. This is different than Model or Database first in that it generates a fluent model rather than using an .edmx file. You can see exactly how it works then.
See the following article about how you can create your entity classes from existing database :
http://blogs.msdn.com/b/adonet/archive/2011/03/15/ef-4-1-model-amp-database-first-walkthrough.aspx
Code generation templates will do the work for you, you don't need to write them if you have an existing db.
For validation, you can create new partial classes under the same namespace and put DataAnottations for your properties. Here is an example for you :
using System.ComponentModel.DataAnnotations;
using System.ComponentModel;
namespace TugberkUgurlu.App1.DataAccess.SqlServer {
[MetadataType(typeof(Country.MetaData))]
public partial class Country {
private class MetaData {
[Required]
[StringLength(50)]
[DisplayName("Name of Country")]
public string CountryName { get; set; }
[Required]
[StringLength(5)]
[DisplayName("ISO 3166 Code of Country")]
public string CountryISO3166Code { get; set; }
[DisplayName("Is Country Approved?")]
public string IsApproved { get; set; }
}
}
}
-Since the database already has defined foreign keys and unique constraints, and so on, how and where to implement the validation for a best and most fluid result for use in ASP.NET MVC3?
These should happen via your generated model. Keys are automatically inferred. If you reverse engineer an existing database the attributes will be created for you. If not, there are basic rules that are followed. The entity framework will attempt to use an auto incrementing primary key for example unless you tell it otherwise via
[DatabaseGenerated(System.ComponentModel.DataAnnotations.DatabaseGeneratedOption.None)]
The relationships are already part of your model so there is your referential integrity, and the data annotations will define the validation rules.
-Is it better to implement Attributes and CustomValidation or to use TryCatch blocks to catch errors from db?
Implement attributes. Define your metadata classes with your attributes in them.
In addition you want to catch any db errors for anything else that is unexpected if your db has additional logic in there not defined in your model (try catch at some level should generally be used anyways for logging purposes_
-Does Validator.TryValidateObject(myModelObject, context, results, true); use validation rules defined only as Attributes or can it use rules defined in EntityTypeConfiguration?
As far as I'm aware only the attributes are used. I'm going to try to test this later though as I'd like a definite answer on this as well :)

How do I use Fluent nHibernate to map a multi-table entity using a foreign key from the primary entity using an FK->PK relationship?

This is the basic example from hbm-style nhibernate.
http://ayende.com/blog/2327/multi-table-entities-in-nhibernate
public class Person
{
public int PersonId {get;set;}
public string Name {get;set;}
public string AddressStreetAddress {get;set;}
public string AddressZipCode {get;set;}
}
In the database, Person has an Id primary key, a name field, and an address foreign key. Address has its own primary key, a street address field and a zip code field.
The correct answer is "Don't do it.". Unfortunately I'm stuck with an entity object that exposes the Id and Name of another entity and those are used elsewhere still. At the moment, this object won't be persisted back to the database through nHibernate.
I think the way to do this is to use the address as the table of the entity and add the Person fields from the Join(). What are the consequences of doing this as an intermediate step in a change-over?
I think the way to do this is to use
the address as the table of the entity
and add the Person fields from the
Join(). What are the consequences of
doing this as an intermediate step in
a change-over?
This was a bad idea because the only Id you could map to is the Id of the address which can be shared between multiple persons.
Instead, add a private/protected property for Address to Person, map Address and reference the address using the following Fluent call.
References(Reveal.Member<Person, Address>("Address")).Column("address_id")
Then, you can use AddressStreetName and AddressZipCode to pass through to Address.StreetName and Address.Zipcode. After that, it's a simple matter of refactoring the rest of the system to be sane again.

Resources