I'm reading a WROX book on LINQ and the author is performing LINQ on a database. Essentially he is accessing the database as an object as shown in the code below.
But I don't see how he expects to "access the database as an object", even the downloaded code gets an error on "db.DirectoryInformation" saying "DirectoryInformation" is unknown.
What am I missing? I would think I first need to create LINQ-to-SQL classes or an ADO.NET EDM or is there even a more direct way to hook LINQ up to a database, i.e. just by creating a database class and that inherits from DataContext?
AdventureWorks db = new AdventureWorks("Integrated Security=sspi");
...
[Database(Name = "AdventureWorks")]
public class AdventureWorks : DataContext
{
//public Table<DirInfo> DirectoryInformation;
public AdventureWorks(string connection) : base(connection) { }
public Table<DirectoryInformation> DirectoryInformation;
}
You can download the whole code here, chapter 1, LINQ.sln.
Look at the end of the Form1.cs source file, the LINQ to SQL database is declared using attributes:
[Database(Name = "AdventureWorks")]
public class AdventureWorks : DataContext
{
//public Table<DirInfo> DirectoryInformation;
public AdventureWorks(string connection) : base(connection) { }
public Table<DirectoryInformation> DirectoryInformation;
}
[Table(Name = "DirectoryInformation")]
public class DirectoryInformation
{
[Column(DbType="varchar(50)")]
public string DirectoryName;
[Column(DbType = "varchar(255)")]
public string DirectoryDescription;
}
Providing the settings with the project define a connection string, this is all you need for a simple mapping of the DirectoryInformation type to the DirectoryInformation table in the AdventureWorks database.
Oh, absolutely you can use vanilla objects with LINQ-to-SQL; you don't even need to subclass DataContext - but you do need to tell it about your model. This is often done with attributes on members (for columns) and types (for tables), but can also be done with an external mapping file (xml). I wonder if they are just over-abbreviating for simplicity... for example, I suspect that the table should be a property:
public Table<DirectoryInformation> DirectoryInformation {
get { return GetTable<DirectoryInformation>(); }
}
The whole "dbml" thing is just there as a designer tool to help you generate the classes; the important code is just decoracted classes (with some conventions on things like navigation properties to make life simper to use). That said, for "quickest": use the designer.
Related
Objective:
Use EF to enter in data from a POST request from an API. The POST request will contain an "ID", that will map the connection string to an enum, which will have the same name connection string name as it has in the Web.config. Create the "base" context object and add the object to the appropriate table.
Note:
I know I can do this using SqlCommand, but I wanted to take a crack at it using entity framework instead, but I hit a wall.
I've used EF for years, but I wanted to make this POST method as global as I can get it. This API will accept numerous requests from numerous different web sites, but all will use the same model. Each websites POST will go into a different database (that's how they are requesting it).
The problem that I foresee is, each "entity" knows what tables it contains. So when one types context.TABLE.Add(object), EF understands that you want to put this "Car" object in the "Car" table (obviously).
Can this be done using a "global" entity???
public class DbConnectionNames
{
public enum DbConnectionStringNames
{
SocHopeHcpEntities = 1, // "1" is passed into the POST to map
XXXXEntities = 2,
......
}
}
<add name="SocHopeHcpEntities" connectionString=".........." />
<add name="XXXXEntities" connectionString=".........." />
.....
var professional = new Professional
{
....
....
};
string connStringContext = Enum.GetName(typeof(DbConnectionNames.DbConnectionStringNames), model.FormId).ToString();
string connectionString = ConfigurationManager.ConnectionStrings[connStringContext].ConnectionString;
using (var context = new ObjectContext(connectionString))
{
context.Professionals.Add(professional); // obviously this doesn't work
context.SaveChanges();
}
EDIT:
My EF is NOT using POCO, but is already based off a DB to begin with. There could be XX number of different databases, all holding the same similar table. I already have a YYYEntities.Context.cs file auto-generated that inherits from DbContext:
public partial class SocHopeHcpEntities : DbContext
{
public SocHopeHcpEntities()
: base("name=SocHopeHcpEntities")
{
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
throw new UnintentionalCodeFirstException();
}
public virtual DbSet<AreasOfWork> AreasOfWorks { get; set; }
public virtual DbSet<Professional> Professionals { get; set; }
}
You still need a context that understands what a Professional is. For example:
public class ProfessionalContext : DbContext
{
public ProfessionalContext(string connectionString)
: base(connectionString)
{
//This line is optional but it prevents initialising the database
//every time you connect to a new database
Database.SetInitializer<ProfessionalContext>(null);
}
public DbSet<Professional> Professionals { get; set; }
}
And use it like this:
using (var context = new ProfessionalContext(connectionString))
{
context.Professionals.Add(professional);
context.SaveChanges();
}
DavidG's answer showed you how to pass a connection string to a strongly typed context that knows the entity types you are dealing with. That context inherits from DbContext which you can use directly as illustrated below.
It is worth noting the generic way that does not involve a context 'object' that is specific to your database.
For example see how ObjectContext is used here:
System.Data.Objects.ObjectContext oc = new System.Data.Objects.ObjectContext("connection string");
oc.AddObject("ProfessionalsTable", professional);
Another example is using DbContext:
System.Data.Entity.DbContext dbc = new DbContext("");
dbc.Set(typeof(Professional)).Add(professional);
The generic approach is better if you also do not know which table you want to insert to, so you can also make the object that you want to insert dynamic.
Right now Im working in a big project, So theres a lot of data and tables going around.
For best practices Im creating a class for every table and object
Its goes like this:
public class Employee
{
private String Name;
public String Name
{
get
{
return Name;
}
set
{
Name = value;
}
}
public Employee(int EmployeeID)
{
/*
GET DATA ROW AND ASSIGN IT TO EVERY PROPERTIE
*
* Name = row("name")
* AND DO THIS FOR EVERY PROPERTIE!
*
*/
}
}
So whats happening here is that I have to assign every propertie from a query in the class constructor.
But imagine a table with like 50+ columns, I have to do this 50+ times and this takes a lot of time.
Theres a way to automate this automate the creation of the 50+ properties and the asignation of the 50+ properties in the class withouth taking a lot of time.
I just wanna find a way to create a class automating the properties assignation from a datarow instead of writting all the columns string to the properties. Something like Entityt Framework but done by me.
Greeting and thanks
There are heaps of examples online to make C# classes from dB tables & stored procedures, research that and POCO's, eg:
Generate class from database table
http://www.codeproject.com/Articles/8397/C-Code-Generator-for-Stored-Procedures
You're not the first to encounter this, best to do a quick google next time.
you should use better entity framework code first approach, it works even if your database is already created.
use a tool to generate the class model, and create a context like:
public class MyContext : DbContext
{
public MyContext (){}
public DbSet<MyModel> MyModel { get; set; }
}
I have a model of my content:
class BaseModel {
public virtual string Content{ get; set; }
// ...
}
To display the data only the model above is fine. But I want to add the functionality to edit the content. So I need to add an attribute to the member content - But this should only happen when the autor press an edit button, not in the regular view of the content.
So I created a second model which inherits from the BaseModel so that I can override the member with my attribute:
class EditableBaseModel : BaseModel {
[UIHint("MyEditor"), AllowHtml]
public override string Content{ get; set; }
}
This works fine, but because of the inheritance EF create an additional column discriminator. It contains the type of the class as string. In my case its always BaseModel because I always convert EditableBaseModel to BaseModel before It gets saved to the database like this:
myBbContextInstance.BaseModels.Add(editableBaseModelInstance as EditableBaseModel);
Thus, the discriminator-column is a waste of space and I want to remove it. I found out that this can be done using the NotMapped-attribute. But this will result in the following exception when I try to save the model:
Mapping and metadata information could not be found for EntityType 'EditableBaseModel'.
It seems that the NotMapped-attribute will let EF know that another class exists that inherits from BaseModel, but EF won't get any information about this class. But thats not what I want. I need to tell EF: EditableBaseModel is nothing it should care about because its only to fit my view, and would be never used for the database.
How can I do that? The only way I found out is to convert the EditableBaseModel instance manually to a BaseModel object like this:
public ActionResult Save(EditableBaseModel editableBaseModel) {
var baseModel = new BaseModel() {
Content = editableBaseModel.Content
// ...
};
myDbContextInstance.BaseModels.Add(baseModel);
}
But this seems not a good way to do that because I have multiplice attributes. And it's also not very flexible because when I add something to the BaseModel, I have to add it also here - Which can result in strange errors.
Mixing EF concepts with MVC concepts into a Model may not fits for both. In this case creating new BaseModel and copy the content of EditableBaseModel into BaseModel as you did, is the right way. You can use AutoMapper for mapping data between two models.
class EditableBaseModel
{
[UIHint("MyEditor"), AllowHtml]
public string Content{ get; set; }
}
public ActionResult Save(EditableBaseModel editableBaseModel) {
var baseModel = new BaseModel();
Mapper.Map<EditableBaseModel, BaseModel>(editableBaseModel, baseModel);
myDbContextInstance.BaseModels.Add(baseModel);
.
.
.
}
The bottom line is that, using inheritance in Entity Framework, you can't represent the same record in the database by two different types.
Stated differently, if you use inheritance in any way, EF can materialize any row in the database to one type only. So what you want is never possible, with or without discriminator.
I think the conversion to and from EditableBaseModel is a viable option. Or wrap a BaseModel in a EditableBaseModel, where the latter has delegate properties like
public string Content
{
[UIHint("MyEditor"), AllowHtml]
get { return _baseModel.Content; }
set { _baseModel.Content = value; }
}
This is a common pattern, called Decorator. Note that in that case (or with your conversion) you should not register EditableBaseModel as an entity in the EF model.
Technically, another approach would be possible. You can materialize any object by DbContext.Database.SqlQuery. You could use BaseModel for display purposes only and use EditableBaseModel as the mapped entity class. BaseModels then, could be materialized by
myBbContextInstance.Database.SqlQuery<BaseModel>("SELECT * FROM dbo.BaseModel");
Of course the query can be parametrized to filter the models. The BaseModels will not be tracked by the context, but as you only want to display them, that's not necessary. This is the only way I see to represent (sort of) one record in the database by another type.
While I mention the technical possibility, that doesn't mean I recommend it. But then, even for the editable option I'd prefer using view models. I don't like this tight coupling between data layer and UI.
Have you considered using a constructor in BaseModel which works in the following way:
public BaseModel(EditableBaseModel editableBaseModel) {
this.Content = editableBaseModel.Content
}
and use it like this:
myBbContextInstance.BaseModels.Add(new BaseModel(editableBaseModelInstance));
I'm using EF5 database first with partial classes. There's a property in my partial class which contains n object which is stored as a column in my database containing XML data. I want to handle the serialization/deserialization of this object when the EF tries to read/write it with a custom getter/setter.
Is it possible to expose the column in my partial class and map it using the EF, without auto-generating a property for it?
ie:
public SomeObject BigComplexObject { get; set; } // forms etc in my app use this
public string BigComplexObjectString // when the EF tries to read/write the column, my custom getter/setter kicks in
{
get { return this.BigComplexObject.ToXmlString(); }
set { this.BigComplexObject = new BigComplexObject(value); }
}
At present, the EF is auto-generating a member for the column so I'm left with two.
Try to change the logic. Leave EF generated property that will be populated with XML string from the database:
public string BigComplexObjectString { get; set; }
Then do the following:
[NotMapped]
public SomeObject BigComplexObject
{
get { return new SomeObject(this.BigComplexObjectString); }
set { this.BigComplexObjectString = value.ToXmlString(); }
}
Don't forget to add [NotMapped] to instruct EF to ignore this property.
Well, we use a little trick for a quite similar case...
We use the property panel (in the edmx file) of our... properties and add something in the "documentation" (summary or long description) line (probably not the best place, but anyway). This can be access by your T4 file.
So you could write something like "useXml" in the property panel, then modify your tt to generate the desired code when (example to get the info in the .tt file)
if (edmProperty.Documentation != null && edmProperty.Documentation.Summary = "useXml")
//generate something special
It would be great to have a better place for "cusom infos" in the edmx, but we didn't find anything better for instant.
I have entity fluently mapped to existing oracle view:
public class MyEntityMap : ClassMap<MyEntity>
{
public class MyEntityMap()
{
ReadOnly();
SchemaAction.None();
//mappings
}
}
I'm querying oracle view for entities and filtering them based on certain criteria, let's say, where created_date more than 14 days. Those entities should be written into the database for future reporting use. For that purpose I've created a table which is exact clone of oracle view in terms of fields. And I'd like to map exactly the same MyEntity to my own table. Something like that:
public class MyHistoricalEntityMap : ClassMap<MyEntity>
{
public class MyHistoricalEntityMap()
{
Table("HistoricalEntities");
//mappings
}
}
Also, I have a service responsible for querying view, but I want to add a method to store my historical entities, smth like below:
public class MyEntityService : IMyEntityService
{
private IRepository<MyEntity> _repository;
...
public IEnumerable<MyEntity> GetEntities(){...}
public void StoreHistoricalEntities(IEnumerable<MyEntity> historicalEntities) {...}
}
So, question is: how do I specify, that I want to (or nhibernate should) use MyEntityMap for querying, but MyHistoricalEntityMap for storing results? Or what other solution can I apply?
Thanks,
You can't use two different mappings for an entity.
What you can do is use custom SQL for loading.