I am trying to map a many to one relationship. I feel I'm close but not quite there.
I have this sensor table:
SensorId
FK_LocationId
Name
etc...
Which holds many data records in the Data Table.
DataId
FK_SensorId
Time
Value
And I am trying to create a Model for this.
public class DataSensor
{
public int Id { get; set; }
public int DataNodeId { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public bool active;
public bool alarm;
}
public class GatheredData
{
public int Id { get; set; }
public int DataSensorId { get; set; }
public DateTime Time { get; set; }
public float value { get; set; }
[ForeignKey("DataSensorId")]
public virtual DataSensor datasensor { get; set; }
}
It should actually be the other way around, at least in my mind. Where the sensor would hold a List<Data> but there is no FK to link that in Sensor. A Data record is just mapped to a sensor by the FK of that sensor.
The problem I'm facing here is that I would have this line in my view now:
#model IEnumerable<DataVisualization.Models.Data>
And instead of looping over my sensors to display the information and then show the data (eventually a chart). I have to loop all the data, somehow organize it how I want and then display it. So I would still need:
#model IEnumerable<DataVisualization.Models.DataSensor>
But this does not give me access to the data since that is in Data and DataSensor does not expose any of that afaik. So I thought about somekind of class that maps them together:
public class DataViewModel
{
public DataSensor dataSensor { get; set; }
public List<GatheredData> gatheredData { get; set; }
}
And my view would require:
#model IEnumerable<DataVisualization.Models.DataViewModel>
This seemed an elegant way but I was not able to make it work. Probably since this would require public DbSet<DataViewModel> dataViewModel { get; set; } in the DbContext and that would produce a awkward table in my database.
So any help on how to create the Model, work with it in the Controller and displaying it in the View would be greatly appreciated.
Edit
What about this Model so I have access to the data connected to this?
public class DataSensor
{
[Key]
public int Id { get; set; }
public int DataNodeId { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public bool active;
public bool alarm;
public virtual ICollection<DataSensor> Data { get; set; }
}
However, this creates a column DataSensor_Id in the database table. This obviously is undesirable since then it would be a one to one.
I am going to leave my other answer below because it still provides valuable information.
This is how you can accomplish just pulling the data from the database for display. You are using the database first approach. I would recommend creating a new project to test this and get accustomed to what is taking place. Now you are going to want to go to tools in the ribbon and select connect to database. Enter the relevant information to connect to the database. Now create new project, if you haven't already. For the purpose of learning create an Asp.Net5 web application with no authentication. Now, go to your NuGet Package Manager Console. Run " Install-Package EntityFramework.MicrosoftSqlServer -Pre ". Once that is completed Run " Install-Package EntityFramework.Commands –Pre " and " Install-Package EntityFramework.MicrosoftSqlServer.Design –Pre ". Once those are installed go to your Project.Json file and in the commands section add "ef": "EntityFramework.Commands" . Now, go to command prompt and cd to your projects directory. The easiest way I have found to do this is to right click your project and open folder in file explorer. Once you do that, go up one level so all you see is one folder. If you see all of the contents of your project then that is NOT the right place. Shift+RightClick on the folder and you should see the option to Open Command Window Here. Click that and once Command Prompt has opened in your project directory. Run
dnvm use 1.0.0-rc1-update1
or I have found that not to work in some cases. If that doesn't work then Run
dnvm use 1.0.0-rc1-final
If neither of these work you need to install 1.0.0-rc1. Once one of those work, Run
dnx ef dbcontext scaffold
"Server=EnterYourConnectionStringHere;Database=YourDataBaseNameHere;Trusted_Connection=True;"
EntityFramework.MicrosoftSqlServer --outputDir Models
Once that is complete you should have your models that were created from the database in the Models Directory. Go to your newly created Context Class in the Models Directory. Once in there you will see an override void OnConfiguring method. Delete that. Open your Startup.cs and put these using statements at the top.
using YourProject.Models;
using Microsoft.Data.Entity;
Now in your ConfigureServices Method in Startup.cs add
var connection =#"Server=YourConnectionString;Database=YourDatabaseName;Trusted_Connection=True;";
services.AddEntityFramework()
.AddSqlServer()
.AddDbContext<YourContextName>(options => options.UseSqlServer(connection));
Then the rest is just creating controllers and views for your newly registered context.
Old Answer Below
Try using the fluent API to specify the relationship. Like this: (Hint: this is in your ApplicationDbContext.)
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
builder.Entity<DataSensor>()
.HasMany(p => p.Data)
.WithOne();
}
public DbSet<DataSensor> DataSensor { get; set; }
public DbSet<GatheredData> GatheredData { get; set; }
And your classes like this:
public class DataSensor
{
public int Id { get; set; }
public int DataNodeId { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public bool active;
public bool alarm;
public virtual ICollection<DataSensor> Data { get; set; }
}
public class GatheredData
{
public int Id { get; set; }
public int DataSensorId { get; set; }
public DateTime Time { get; set; }
public float value { get; set; }
[ForeignKey("DataSensorId")]
public virtual DataSensor datasensor { get; set; }
}
You can also do this by convention like this
public class DataSensor
{
public int Id { get; set; }
public int DataNodeId { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public bool active;
public bool alarm;
public virtual ICollection<DataSensor> Data { get; set; }
}
public class GatheredData
{
public int Id { get; set; }
public int DataSensorId { get; set; }
public DateTime Time { get; set; }
public float value { get; set; }
public virtual DataSensor datasensor { get; set; }
}
or by data annotations like this
public class DataSensor
{
public int Id { get; set; }
public int DataNodeId { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public bool active;
public bool alarm;
public virtual ICollection<DataSensor> Data { get; set; }
}
public class GatheredData
{
public int Id { get; set; }
public int DataSensorId { get; set; }
public DateTime Time { get; set; }
public float value { get; set; }
[ForeignKey("DataSensorId")]
public virtual DataSensor datasensor { get; set; }
}
If you do this by convention and it doesn't work, data annotations could help map them. If all else fails then the fluent API will override everything and map the relationship.
Now, for how to display this data. If you are just trying to display the data and not edit it then I think creating a partial view will be your best bet. In your shared folder create a blank view. Add your model to the new view.
#model IEnumerable<DataVisualization.Models.GatheredData>
Then do a foreach loop to iterate through that data.
#foreach (var item in Model)
{
<p>#Html.DisplayFor(modelItem => item.Id)</p>
<p>#Html.DisplayFor(modelItem => item.Time)</p>
<p>#Html.DisplayFor(modelItem => item.Value)</p>
}
Then back in your main View for the Datasensor put the following where you want the data.
#Html.Partial("StringNameOfThePartialView", Model.Data)
The first overload is the name of the partial view, and the second is the model data to be passed to that view.
Related
Using Entity Framework Code first I have a class that holds data for a drop-down list. The same class holds records that are sub-items for the items in the main list. Ultimately this will create a cascading set of drop-down lists.
I am trying to figure out how to make the navigation property for the class link back to itself. The issue class is the one that I am using to populate the drop-down list. The Complaint class also has a link to the Issues class but does not need a link back to the subcategory.
public class Issue
{
public Issue()
{
Complaints = new List<Complaint>();
SubIssues = new List<Issue>();
}
[Key]
public int IssueID { get; set; }
public string Name { get; set; }
public bool IsSubCategory { get; set; }
[ForeignKey("IssueID")]
public ICollection<Issue> SubIssues { get; set; }
public virtual ICollection<Complaint> Complaints { get; set; }
}
public class Complaint
{
public Complaint()
{
}
public int ComplaintID { get; set; }
public string Name {get; set;}
[ForeignKey("IssueID")]
public virtual Issue Issue { get; set; }
}
I did something similar, but actually did only have a parent reference in the children. Either way this should work.
public class Folder
{
[Key]
public int Id { get; set; }
// Some Property
public string Name { get; set; }
// They foreignkey for Many-side
public virtual Folder Parent { get; set; }
// The list for One-side (Not tested in my application)
public virtual ICollection<Folder> SubFolders { get; set; }
}
It is same as a regular one-to-many relation, just all the references are within same entity.
I have a database and I'm accessing it via EF.
public partial class Project
{
public int ProjectID { get; set; }
public string Name { get; set; }
public virtual ICollection<ProjectAssets> ProjectAssets { get; set; }
}
public partial class ProjectAssets
{
public int MappingID { get; set; }
public int ProjectID { get; set; }
public int AssetID { get; set; }
public virtual Project Project { get; set; }
public virtual Asset Asset { get; set; }
}
public partial class Asset
{
public int AssetID { get; set; }
public string Name { get; set; }
public short Type { get; set; }
public virtual ICollection<ProjectAssets> ProjectAssets { get; set; }
}
So, my program have only 1 active Project in the time.
I want to be able to bind to Project and display as a tree or some other way all Assets and I want to be able to create new Asset or add existing Asset what belongs to other project.
If I will use the generated entities I would not be able to manage that all so I need some rules. I've already found good impl. of repositories, but still don't know how to create rules.
Do I need to create something like:
public class WorkProject : Project
{
public WorkProject(Project projject){...}
WorkAsset CreateAsset(){...}
void AddAsset(Asset asset){...}
}
As far as I understand your question, you want to control the graph of entities which are related to a project object. You can leave the repository layer intact and put another layer (business layer) on top of it to enforce the rules.
I am essentially am trying to find a clean way to pull in data from another table. Below is a simplified version of my model. My goal is to put the platform name in the userplatform. I would like the cleanest way to do this so I assume with automapper or directly in my repository.
When I try to put a virtual reference to Platform in User Platform my code gets an error that we have a loop of cascading deletes.
Any ideas on how to resolve this problem?
public class User
{
public int UserID { get; set; }
public virtual ICollection<UserPlatform> UserPlatform { get; set; }
}
public class UserPlatform
{
public int UserPlatformID { get; set; }
public String PlatformName { get; set; }
public int UserID { get; set; }
}
public class Platform
{
public int PlatformID { get; set; }
public string Name { get; set; }
}
Alternatives
Db: Denormalize your data so that the information is stored in your user table.
Repository: Do a join inside
Repository: Do two different queries and manually build the User object.
So, i have this class here:
public class Platillo
{
public virtual int ID { get; set; }
public virtual String NombrePlatillo { get; set; }
public virtual int idRestaurante { get; set; }
public virtual String DescripcionPlatillo { get; set; }
public virtual bool esAprobado { get; set; }
public virtual bool esDisponible { get; set; }
public virtual double precio { get; set; }
public virtual DateTime vigenciaPlatillo { get; set; }
public virtual List<ListaIngredientes> listadeIngredientes { get; set;}
}
I've created a strongly typed PlatilloController that makes all basic CRUD operations. The problem is, the View renderes everything but the List.
My idea is to create a List that allows to add new ingredients(Ingredientes) and the amount of servings (Porciones) for each one on a dish (Platillo).
public class ListaIngredientes
{
public virtual int ID { get; set; }
public virtual Ingrediente ingrediente { get; set; }
public virtual int porciones { get; set; }
}
public class Ingrediente
{
public virtual int ID { get; set; }
public virtual String NombreIngrediente { get; set; }
//...
}
So, what i was thinking was to implement a PartialView that rendered a list of every ingredient on the dish, and that allowed to add new ingredients. How exactly do I do that? And, since i plan on creating and updating new ingredients on the same page, i'm sure i should be taking AJAX into account. How exactly can i use Ajax to Create and display ListaIngrediente's list entries?
Just a sample using a partial view page, try this:
#model <Project>.Models.Platillo
#foreach(ListaIngredientes ing in listadeIngredientes)
{
<div>#ing.ID</div>
<div>#ing.Ingrediente.NombreIngrediente</div>
}
I am alittle bit confused about your design why would you use a list public
virtual List<ListaIngredientes> listadeIngredientes { get; set;} I would start but first creating a Platillo foreign key in your ListaIngredientes that would match with Platillo something like PlatilloID so now you would have a list of ListaIngredientes that match the Platilloios and it ingridients.
and then sure you can create an ajax partial view at which you can add Ingrediente and then match specific ingridients with your Platilloio on a separate view in another word create separately ingridiets and Platilloio and then on another view add ingridiets from the ingridients in your Ingridients table to Pelatio.
I'm trying to map the results of a stored procedure into a model that contains another model several times. I'm not sure if this is possible, but wanted to ask and see if this is a valid approach, or if it would be better to define everything out individually.
My model classes look like this:
public class ClientSummary {
public virtual int Id { get; set; }
public virtual int Client_ID { get; set; }
public virtual string Client_Name { get; set; }
public virtual string State { get; set; }
public virtual EDITotal Totals { get; set; }
public virtual EDITotal In_Totals { get; set; }
public virtual EDITotal Out_Totals { get; set; }
public virtual EDITotal Direct_Totals { get; set; }
public virtual EDITotal CPN_Totals { get; set; }
}
public class EDITotal {
public virtual int Count { get; set; }
public virtual double Charges { get; set; }
public virtual double StateSavings { get; set; }
public virtual double PPOSavings { get; set; }
public virtual float PPO_Pct_Bill { get; set; }
public virtual float PPO_Pct_State { get; set; }
public virtual int Unique_TaxIds { get; set; }
}
What I'm not sure of is what my class map would look like in Fluent NHibernate, or if something like this is possible. I'm mainly trying to keep things tidy, and reusable. I'm sure I'll have other reports that will use similar metrics. Am I going about this the right way, or do I really need to define a full model for each report I build? This is all taking place inside a MVC Web application.
Thanks in advance!
Yes this is indeed possible and right or wrong you can get it working with the way you have your classes setup. To do this, you can use a mapper like this:
public class ClientSummaryMappingOverride : IAutoMappingOverride<ClientSummary>
{
public void Override(AutoMapping<ClientSummary> mapping)
{
mapping.References(x => x.Totals, "Totals_id");
mapping.References(x => x.In_Totals, "In_Totals_id");
mapping.References(x => x.Out_Totals, "Out_Totals_id");
mapping.References(x => x.Direct_Totals, "Direct_Totals_id");
mapping.References(x => x.CPN_Totals, "CPN_Totals_id");
}
}
Once you have your map configured, you just need to make sure your Stored Procedure or SQL Query returns the ClientSummary records with the appropriate "Totals_id" type fields. NHibernate will pick up those ids and map them to the correct data (Lazy Load I believe, depending on your conventions or other mappings).