EF 6.0 - Map complex type to same table as parent property - entity-framework-6

I have looked at the following:
Entity framework code first map multiple complex types of the same type to a table
Given the example code:
[Table("TXLifeRequest", Schema = "txlife")]
public partial class TXLifeRequest
{
public virtual OLI_LU_BOOLEAN PendingResponseOK { get; set; }
...
}
[Table("OLI_LU_BOOLEAN", Schema = "txlife")]
public partial class OLI_LU_BOOLEAN {
public string tc { get; set; }
public string Value { get; set; }
}
I would like to structure the database so that the OLI_LU_BOOLEAN is not in a new table, rather to be two new columns in the TXLifeRequest table as something like TXLifeRequest.PendingResponseOK_tc and PendingResponseOK _Value.
There is no fluent code in the existing context. Is there a way to do this either by fluent or attrubutes so that the class structure is intact but the tables are combined?
Update:
I have tried the following but it creates a new table TXLifeRequest1 for all of the OLI_LU_BOOLEAN properties. How would I specify these as properties of same table?
modelBuilder.ComplexType<OLI_LU_BOOLEAN>()
CreateTable("imsparamed.TXLifeRequest1",
c => new
{
Id = c.Int(nullable: false, identity: true),
PendingResponseOK_Value = c.String(),
PendingResponseOK_Id = c.Int(nullable: false)
})

The solution is to create a complex type:
modelBuilder.ComplexType<OLI_LU_BOOLEAN>().Ignore(i => i.Value);

Related

Add or remove column mapping at runtime for linq2db

I have a scenario where if certain features are deployed then a number of columns will be there in some tables otherwise won't so the mapping of Entities and Columns is not static. I need to add/remove the mapping at runtime. Is there any way?
Prepare a new MappingSchema and pass to DataConnection constructor.
Consider you have the following class:
[Table]
class SampleClass
{
[Column] public int Id { get; set; }
[Column] public int Value { get; set; }
}
To remove column from full object materialization, do the following:
var ms = new MappingSchema();
ms.GetFluentMappingBuilder()
.Entity<SampleClass>().Property(e => e.Value).IsNotColumn();
// cache somewhere this schema
using (var db = new DataConnection(ms))
{
var result = db.GetTable<SampleClass>().ToArray();
}
Remember, better to cache this new MappingSchema and reuse. Otherwise you will never have cache hit and you'll lose performance.

Cannot map LINQ to Entities

I'm not very clear with writing linq queries. I write a query to select only certain columns from a table using linq lambda expression and I get the error that linq cannot be constructed to entities. The same query when I write using linq to select all columns I don't get any errors and I get all the columns, which i later filter out in the view. But I want to use the lambda to select only certain columns.
Code snippet:
ViewModel:
public class StaggingInternalCashExceptionViewModel
{
public OutputCash OutputCash { get; set; }
public IEnumerable<StaggingInternalException> StaggingInternalException { get; set; }
//list of results of Stagginginternalcashexception
}
Controller:
public ActionResult Exceptionstest(string dd1, string dd2, string dd3)
{
StaggingInternalExceptionViewModel _app = new StaggingInternalExceptionViewModel();
_app.StaggingInternalException = db2.StaggingInternalExceptions.Where(x => x.Level1 == dd1 && x.Level2 == dd2 ).Select(i => new StaggingInternalException
{
StaggingInternalRowID = i.StaggingInternalRowID,
Category = i.Category,
EnterText1 = i.EnterText1,
InternalAmount = i.InternalAmount,
ExternalAmount = i.ExternalAmount
});
_app.StaggingInternalException = (from p in db2.StaggingInternalExceptions
where p.LoadID==loadid && p.Level1 == dd1 && p.Level2 == dd2 select p);
}
In the above code, the lambda expression throws an error when I'm trying to select only certain columns from the table or if we are speaking in terms of entity classes, only certain properties. But the query returns all the columns. Should I be using DTOS? I'm not sure what the use of data transfer objects is. Some explanation on this would be great. Thanks.
You need to use a DTO.
A dto is just an object that you map your result to. In your case it would be
public class StaggingInternalExceptionViewModel
{
public int StaggingInternalRowID { get; set; }
public int Category { get; set; }
... //rest of properties
}
You need to change your StaggingInternalCashExceptionViewModel to use the StaggingInternalException DTO
public class StaggingInternalCashExceptionViewModel
{
public OutputCash OutputCash { get; set; }
public IEnumerable<StaggingInternalExceptionViewModel> StaggingInternalException { get; set; }
//list of results of Stagginginternalcashexception
}
Then your expression stays the basically the same but you select a new StaggingInternalExceptionViewModel instead of StaggingInternalException
StaggingInternalExceptionViewModel _app = new StaggingInternalCashExceptionViewModel();
_app.StaggingInternalException = db2.StaggingInternalExceptions.Where(x => x.Level1 == dd1 && x.Level2 == dd2 ).Select(i => new StaggingInternalExceptionViewModel
{
StaggingInternalRowID = i.StaggingInternalRowID,
Category = i.Category,
EnterText1 = i.EnterText1,
InternalAmount = i.InternalAmount,
ExternalAmount = i.ExternalAmount
});
Linq to Entities doesn't let you project a query using an entity type because you can end up losing information at loading an entity partially and trying later to save that entity to your DB. So, you must project your queries when you need partial information of an entity whether using a DTO or an anonymous type.
If you need to use the entity type, then don't project using Select method, the only thing is you're going to load all the properties, but I think this is not the case because you don't need all the data ;).

ASP.NET MVC Webgrid display multiple columns in a single row

I have a Asp.net MVC grid.
My problem is I need to display multiple columns in a single row.
For example:
Name Date Compensation
Id USD - 99999
Grade INR - 99999
The above layout is a single row in the grid.
All the columns (Name, Id, Grade, Curency1, Amount1, Currency2, Amount2 ) are available in a single record as separate columns. Here Currency1 means USD and Currency2 means INR.
Any ideas how to do this. I am using a strongly typed model and EF6.
I think the best way to do this would be to create a separate 'type' and model for each multi-faceted column, then try to display this type in the webgrid (which I show is possible in the latter part of my example).
For example:
Create a new 'type' (or 'column') class called CompensationColumn:
...
using System.Web.Mvc;
namespace yourproject.Columns // I put this in its own namespace/folder - you don't have to
{
public class CompensationColumn
{
public string Currency1 { get; set; }
public int Amount1 { get; set; }
public string Currency2 { get; set; }
public int Amount2 { get; set; }
public CompensationColumn(string currency_1, int amount_1, string currency_2, int amount_2)
{
Currency1 = currency_1;
Amount1 = amount_1;
Currency2 = currency_2;
Amount2 = amount_2;
}
}
}
Then create a file called CompensationColumn.cshtml in the yourproject/Shared/EditorTemplates folder (if the Shared folder doesn't exist you can also create a your view/DisplayTemplates folder). Define how this column will look, as if it was a custom 'type' (modify this to your liking):
#model yourproject.Columns.CompensationColumn
#if (Model != null)
{
#Model.Currency1<text> - </text>#Model.Amount1<text><p/></text>
#Model.Currency2<text> - </text>#Model.Amount2
}
else
{
}
Then in your Models folder, create a partial class to extend your current EF table model (file name shouldn't matter). I am going to assume your table is 'employee_table'. I am also adding Metadata for the model in this class as it is a good place to put it if you are using a database-first design:
using System.Web.Mvc;
using yourproject.Columns;
namespace yourproject.Models
{
[MetadataType(typeof(EmployeeModelMetaData))] // This links the metadata class below
public partial class employee_table // This should be the EF class name
{
[DisplayName("Compensation")]
public CompensationColumn Compensation { get; set; } // Here we add a new field for your row
}
public class EmployeeModelMetaData
{
// copy your EF class fields here and decorate them with dataannotations. This is helpful
// if you are using a database-first design as it won't get overwritten when db changes.
[DisplayName("Id")]
public int emp_id { get; set; }
[DisplayName("Amount")]
[DisplayFormat(DataFormatString = "{0:c}", ApplyFormatInEditMode = true)]
public int emp_amount1 { get; set; }
// etc . . .
}
}
I make a few assumptions here about a database-first design, but you should be able to figure out how to adapt it to a code-first design if needed.
If you also need to edit elements this column type together, then you would need to create a model binder, but I'm not going there since you only mentioned displaying it.
To get the display template to display in the webgrid, you will need to format: the columns of the webgrid. In your view with an IEnumerable model (e.g. your Index view):
#{
var grid = new WebGrid(Model);
List<WebGridColumn> columns = new List<WebGridColumn>();
WebGridColumn col = grid.Column(columnName: "Col3", header: "Compensation", format: (item) =>
{
yourproject.Columns.CompensationColumn c = item.Compensation; return Html.DisplayFor(model => c);
} );
columns.Add(col);
}
#grid.GetHtml(columns: columns)
This last snippet I adapted from Frédéric Blondel's code here

Simple approach to CRUD intersection table in MVC ASP.NET and EF?

I am using C#, MVC3, EF5, SQL Server 2008 R2.
I have an intersection table ie
Lecturer -< LecturerCourse >- Course
The list of Lecturers are populated.
When I add a course, it would be neat to have a list of Lecturers that I could select from, that teach the course in question. When I save the new Course record, this multiselect also should save its data back to the "LecturerCourse" table via Model Binding.
I am using EF5.
Can you recommended a simple and standard approach to solving CRUD for a join, ie "LecturerCourse", table? I have looked online, but some of the approaches seem very complicated.
Many thanks.
Alright, it's going to be a long one. To allow this to happen in "one page" (through POST, or you could use Ajax, technically), you need a combination of a Get and Post version of the method and to construct your view model correctly. Below are the classes that I will use for demonstration purposes:
public class NewCourse
{
[Required]
public string Name { get; set; }
// And your other properties
public int[] LecturerIds { get; set; }
}
public class ViewLecturer
{
public int Id { get; set; }
public int Name { get; set; }
}
public class NewCourseViewModel
{
public NewCourse Course { get; set; }
public IEnumerable<ViewLecturer> Lecturers { get; set; }
}
NewCourseViewModel will be the model for the View (see below). ViewLecturer will give you a lighter mapping between your available Lecturer and the information required to Add to them.
As for the Controller:
public class CourseController : Controller, IDisposable
{
private Lazy<YourContext> lazyContext =
new Lazy<YourContext>(() => new YourContext());
private YourContext Context
{
get { return lazyContext.Value; }
}
public ActionResult New()
{
var model = new NewCourseViewModel {
Course = new NewCourse(),
Lecturers = Context.Lecturers
.Select(l => new ViewLecturer { Id = l.Id, Name = l.Name })
};
return View(model);
}
[HttpPost]
public ActionResult New(NewCourse course)
{
if(ModelState.IsValid)
{
var lecturers = course.Lecturers
.Select(l => new Lecturer { Id = l.Id })
.ToList();
foreach(var lecturer in lecturers)
Context.Lecturers.Attach(lecturer);
var newCourse = new Course {
Name = course.Name,
// ... and the rest of the mapping
Lecturer = lecturers
};
context.Courses.Add(newCourse);
context.SaveChanges();
// Could have to handle DbUpdateException if you want
return RedirectToAction(...);
}
return View(new NewCourseViewModel {
Course = course,
Lecturers = Context.Lecturers
.Select(l => new ViewLecturer { Id = l.Id, Name = l.Name })
});
}
public void Dispose()
{
if(lazyContext.IsValueCreated)
lazyContext.Value.Dispose();
}
}
Your first New method will give you the entry point for your Course creation page. The rest of the validation and actual adding will be done through the [HttpPost]overload. As for your View (that should be in the ~/Views/Course/New.cshtml):
#model NewCourseViewModel
// ... Then when you are ready to begin the form
#using(Html.BeginForm("New", "Course", FormMethod.Post))
{
// Your List of Lecturers
#Html.ListBoxFor(m => m.Course.LecturerIds,
new MultiSelectList(
Model.Lecturers,
"Id",
"Name",
m.Course.LecturerIds ?? new int[0]
))
// Your Other Model binding
}
When the submit button will be pressed, the action matched will be the New(NewCourse course). The names are important because of the way the HtmlHelpers generate their Ids. Because we are only included one property of the whole view model, it will match the parameter name course based on the view model's Course property. You will get a list of Ids for the Lecturers which you will be able to use to attach to the DbContext and add directly to the new Course model (Entity Framework will do the rest). In cases where there was a problem, we can get back the list of lecturers and re-use the same NewCourse in the view model.
Now this is example is very basic but it should give you a good starting point as to how you can structure your view model.

DeleteOnNull Error

I've got a set of DB objects sitting in an EntitySet on my main object definition. This handles additions and updates fine, but I found the removing items from the list didn't result in the database records being deleted, so I had to create a method in the data repository object to delete the records as the data object doesn't have access to the data-context in which it is being used.
I was looking to see if I could bring this delete into the main object and I found the DeleteOnNull attribute to the association, but when I use it, I get an error "DeleteOnNull can only be true for singleton association members mapped to non-nullable foreign key columns". My code is:
private EntitySet<UserSite> _userSites = new EntitySet<UserSite>();
[Association(Name = "User_UserSites", Storage = "_userSites", ThisKey = "UserID", OtherKey = "UserID", DeleteOnNull=true)]
public IList<UserSite> UserSites { get { return _userSites; } set { } }
my usersite object is
[Table(Name="UserSite")]
public class UserSite
{
[Column]//(IsPrimaryKey = true)]
public int UserID { get; set; }
[Column]//(IsPrimaryKey = true)]
public string Site { get; set; }
[Column]
public bool DefaultSite { get; set; }
[Column(IsPrimaryKey = true, AutoSync = AutoSync.OnInsert)]
public int UniqueID { get; set; }
}
Can I use DeleteOnNull to keep all my data update methods within my main user object, or do I have to handle the deletes at the repository level?
DeleteOnNull is only for singleton associations. So you can put it on UserSite.User but not on User.UserSites. It's still not quite as automatic as you'd like it to be, though. There is an example here.
It's hard for LINQ to SQL to infer the behavior you want, because it can't guess if you want composition or aggregation, so it chooses the safe guess (aggregation).

Resources