Fluent NHibernate Duplicate Columns - vb.net

I am having some redundant primary key issues.
I have an Item which contains many reports. I have mapped them as shown below. I can do Session.QueryOver(Of Item).List and there are no extra columns generated. I can also do Session.QueryOver(Of Report).List and there are no extra columns generated.
However, once I try to traverse the relationship from Item to Reports, I get the SQL query shown below. Can anyone tell me why? Thanks in advance!
Item Mapping:
Public Class ItemMapping
Inherits ClassMap(Of Item)
Public Sub New()
Table("Items")
Id(Function(x) x.ItemID)
HasMany(Function(x) x.Reports).KeyColumn("ItemID").Inverse().Cascade.All()
End Sub
End Class
Report Mapping:
Public Class ReportMapping
Inherits ClassMap(Of Report)
Public Sub New()
Table("Reports")
Id(Function(x) x.ReportID)
References(Function(x) x.Item).Column("ItemID")
Map(Function(x) x.ReportName)
End Sub
End Class
SQL Result:
SELECT repor0_.ItemID as ItemID1_,
repor0_.ReportID as Rep1_1_,
repor0_.ReportID as Rep1_4_0_,
repor0_.ReportName as Rep2_4_0_,
repor0_.ItemID as ItemID4_0_ FROM dbo.Reports repor0_ WHERE repor0_.ItemID=#p0;#p0 = 1266 [Type: Int32 (0)]

This is not a bug according to nhusers group. Apparently NHibernate uses one column for the ID and second one for the foreign key. There are also other cases where some of the columns are sent twice. According to the thread it is not worth it to optimize the extra column away because it doesn't generate additional I/O usage and in normal cases the extra column does not cause too much network traffic.

I do not see 'reportdate' anywhere in your presented mapping files, while it is there in your query therefore I suspect there are other mappings in your project that we currently do not see?

Related

Do I really need association mapping between User and Role? Why? When is it OK to omit it?

Do I need to complicate things like that? Can't I just save my User with a filed List<Roles> without bothering about association mapping? Why and when (in what cases) is it needed and when is it OK to avoid this? What problems can I run into without such mapping? Shall it always be bidirectional or unidirectional is also OK?
CascadeType.MERGE or CascadeType.ALL? I see both variants (see code below).
I see that many Github projects in login-user-and-admin apps define User class like this:
#Entity
#Table
public class User {
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
private int userId;
private String userName;
## Heading ##
private String password;
#ManyToMany(cascade=CascadeType.MERGE, fetch=FetchType.EAGER)
#JoinTable(name="user_authority",
joinColumns={#JoinColumn(name="USER_ID", referencedColumnName="userId")},
inverseJoinColumns={#JoinColumn(name="AUTHORITY_ID", referencedColumnName="id")})
private Set<Authorities> authorities= new HashSet<Authorities>();
I read these, but still no clue.
What is the benefit to use of Association Mapping in Hibernate
https://stackoverflow.com/questi## Heading ##ons/62611075/roles-permissions-and-user-roles-proper-mapping
Do I really need to define mapping association in my entities?
Latter says no mapping may cause problems but provides no explanation - what problems, why, in what specific cases (always? in all cases?)

How to limit the properties needed for the view from the model

I am working very hard to understand the concept of Entity Framework and Models by building a new MVC Architecture Solution. I have started only with two Models that are identical to an (EXISTING DATABASE - That I must model after [Maybe comeback and re-factor later]), with a lot more models to come.
I get the data back to the VIEW no problem, however how do I scale down the CONTROLLER to only query items I need? In this example I have the code committed out (see below), but if I cast .ToList() it throws an exception because that is not the Model Type. I am sure I am missing something very simple, but I am stuck. Any help would be great.
VIEW
#ModelType IEnumerable(Of CompanyName.Models.QAs)
CONTROLLER
Private ReadOnly _db As New Context
Function Faq() As ActionResult
'Dim query As List(Of ShowFaqsModels)
'query = From f In _db.Faqs _
' Where Not f.Hk_DeletedDt.HasValue _
' Or f.Hk_DeletedDt = New DateTime(1900, 1, 1) _
' And f.Active = 1 _
' Order By f.CategoryId Descending _
' Select f.Question, f.Answer
Return View(_db.Faqs)
End Function
MODEL
Imports System.ComponentModel.DataAnnotations
Namespace Models
Public Class QAs
<Key>
Public Property QuestionId As Integer
Public Property CategoryId As Integer
Public Property Question As String
Public Property Answer As String
Public Property Active As Integer
Public Property Hk_CreatedDt As DateTime
Public Property Hk_ModifiedDt As DateTime
Public Property Hk_DeletedDt As System.Nullable(Of DateTime)
End Class
End Namespace
************ EDIT **********
CONTROLLER
Function Faq() As ActionResult
Dim faqs = From f In _db.Faqs _
Where Not f.Hk_DeletedDt.HasValue _
Or f.Hk_DeletedDt = New DateTime(1900, 1, 1) _
And f.Active = 1 _
Order By f.CategoryId Descending _
Select New FaqViewModel With {
.Question = f.Question,
.Answer = f.Answer
}
Return View(faqs)
End Function
Addition - Created a new Folder called "ViewModels" --- Did this to Only Use the Data need in the View.
VIEWMODELS
Imports System.ComponentModel.DataAnnotations
Namespace ViewModels
Public Class FaqViewModel
Public Property Question As String
Public Property Answer As String
End Class
End Namespace
Thanks again to the contributors on this. I am starting to figure out this puzzle and architect this solution. Yes yes I know you can separate out in to other projects, but this site is not needed for that.
Your model as you're describing it is your data model. The best practice for passing or accepting information to/from your view(s) is to use a new class as a view model. It will have only the information necessary for the view and nothing else.
The catch is that these are not always a 1 to 1 mapping (though some of might be). For example, my view models routinely have other information on them, such as collections required for dropdowns, boolean flags indicating if certain areas of the page should be rendered, api keys needed to passing along to javascript resources. It all depends on what your view's needs, but the ideas is that you give the view everything it requires, it should not have to go out and get it itself, unless there's no other way (which does happen in my experience).
Translating between data model and view model is something people have created specific tools for (like AutoMapper), just be aware that most rely on naming conventions of your object's properties being the same, and most would argue it's a bad practice to use an automapper-like solution for accepting information back from the browser.
You are trying to return "...(Select f.Question, f.Answer).ToList()" which would not result in a model of type CompanyName.Models.QAs.
Therefore either return the whole f.ToList() OR
Use ViewModels if you think that the Model has so many extra properties that you wont need all of them in your view. ViewModels are also like models but they are for your views in contrast with Models which basically reflect your database tables/relations in essence. If your view needs only 2 fields out of maybe 50 fields in your model than make a ViewModel for that view.

Cannot insert explicit value for identity column

I'm getting the above error when creating a new record. I don't want to insert the identity -- the database has it auto generated and that is great.
Here is the exact exception:
[System.Data.UpdateException]
{"An error occurred while updating the entries. See the inner exception for details."}
{"Cannot insert explicit value for identity column in table 'PartRevisions' when IDENTITY_INSERT is set to OFF."}
Here are the mappings:
Public Class PartContext
Inherits DbContext
Public Property Parts As DbSet(Of Part)
Public Property PartRevisions As DbSet(Of PartRevision)
Protected Overrides Sub OnModelCreating(modelBuilder As DbModelBuilder)
MyBase.OnModelCreating(modelBuilder)
modelBuilder.Entity(Of PartRevision)().HasKey(Function(r) r.Id).Property(Function(r) r.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity)
End Sub
End Class
<Table("Parts")>
Public Class Part
<Key(), DatabaseGenerated(DatabaseGeneratedOption.Identity)>
Public Property Id As Integer
Public Property PartNumber As String
Public Property Owner As String
End Class
<Table("PartRevisions")>
Public Class PartRevision
Inherits Part
Public Property OriginalId As Integer
Public Property RevisionDate As DateTime
Public Property RevisionNumber As Integer
Public Property RevisionBy As String
End Class
If I don't use inheritance it works fine. If I make Id overridable and also specify the attributes on the sub class it still doesn't work.
I'm doing the OnModelCreating stuff just because I'm trying to get it to work. I feel like it should work without this. Of course it doesn't even work with this...
The following query works fine when I execute it in SQL Management Studio:
insert into PartRevisions (originalid, revisiondate, revisionnumber, revisionby, partnumber, owner)
values (1, '1/1/2013', 1, 'eep', '123', 'ME')
Here is a gist with the full program. I was trying this out in a test project because I assumed I'd run into some issues doing inheritance in EF (never done yet).
https://gist.github.com/eyston/4956444
Thanks!
The PartRevisions table must not have the Id column set as an autogenerated identity, only the table Parts for the base type. The two tables have shared primary keys. EF joins the two tables when it queries a PartRevision and it inserts rows into both tables if a PartRevision entity is inserted. Because both rows must have the same Id only one can be an identity.
Either remove the auto identity property from the "Id" column. Or alternatively you can use in your Query/Stored procedure. This will enable to to enter explicit Id values into your table even if auto identity on column is set. (Though not a good idea to use always but its good for fixes)
SET IDENTITY_INSERT dbo.YourTableName ON;
GO
Then after each table's inserts:
SET IDENTITY_INSERT dbo.YourTableName OFF;
GO

Entity Framework 4.2 table per hierarchy group by discriminator

I am working on a project using an EF 4.2 code first model. This model contains a TPH inheritance structure for products. I need to group the polymorphic results of this inheritance model on the discriminator and am running into some issues.
The entity framework does not expose the discriminator to complete this grouping. My first question is can I get direct access to this discriminator? My reading and experience is telling me no, so I came up with this solution that sort of works. It is not performing well and I am not happy with how it will need to be maintained.
My classes look something like this (simplified):
Public MustInherit Class Product
<key()>
Public Property ProductID as integer
<StringLength(50, ErrorMessage:="Max 50 characters")>
<Required(ErrorMessage:="Product name is required")>
Public Property Name as String
<TimeStamp()>
Public Property Time_Stamp as DateTime = DateTime.Now()
End Class
Public Class Desktop
Inherits Product
<StringLength(50, ErrorMessage:="Max 50 characters")>
<Required(ErrorMessage:="Processor is required")>
Public Property Processor as String
End Class
Public Class Monitor
Inherits Product
<Required(ErrorMessage:="Monitor size is required")>
Public Property Size_Inches as Integer
End Class
I built an extension method that takes a product and returns it's basetype name as a string.
<Extension()>
Public Function ProductType(ByVal inProduct as Product) as String
ProductType = inProduct.GetType().BaseType.Name
End Function
With that, I built this structure to group the results of product by type so I can run through them:
Dim tmpProducts = db.Products.ToList()
Dim GrpProducts = tmpProducts.GroupBy(Function(prod) prod.ProductType) _
.Select(Function(s) New With {.ProductType = S.Key,
.Products = S })
I can now loop through the list to get the behavior I want, but the performance is not ideal and I am concerned it will be unacceptable as the number of products grows.
For Each ProductGroup in GrpProducts
Dim TypeName as String = ProductGroup.ProductType
Dim TypeProducts = ProductGroup.Products
Next
Also, this can give me easy access to shared properties (Name) but now I don't have many options to cast these into their real type, maybe a select case around TypeName. . .
Any recommendations are appreciated, also please forgive any code errors above, I retyped the examples from memory as I don't have access to the project at the moment.
A solution would be to model a bit more, and have a new entity ProductType having a property Name. Then you would have a simple 1-N relationship between Product and ProductType. I have not used EntityFramework, but with NHibernate you could easily make the framework always join that table on queries, so that it would not return a proxy for ProductType for each Product, which could harm performance.
As an add-on, in the future ProductType could develop other interesting properties (such as values that are common for every Product of that ProductType), so it adds flexibility to your solution, although it does have the immediate cost of adding another table to your database.
Following Linq query should get you a way to solve group by discriminator
from a in db.Records
group a.ID by new
{
Name= a is Audio ? "Audio" :
a is Video ? "Video" :
a is Picture ? "Picture" :
a is Document ? "Document" : "File"
} into g
select new
{
Name = g.Key.Name,
Total = g.Count()
}

objectcontext vs datacontext

i'm just new in developping silverlight, and i created a linq to sql connection and a service domain class. I want to get data from 2 tables which have a 1 to many relation into a datagridview. To do this i need to state include commands in my metadata and service domain class , but to do this i need to have an objectcontext instead of a datacontext(that i'm currently having ) can someone help me with this matter so i can use the include statement to get querys for my detail-grid
edit:
I've done what u said added the
"<IncludeAttribute()> _"
Public Property SubgroepIndustries As EntitySet(Of SubgroepIndustrie)
but i get this error message:
Error 1 'Include' is not a member of 'System.Data.Linq.Table(Of ILA4.HoofdgroepIndustrie')
edit 2:
when i try to use the include in my domain service class not the metadata so
Return Me.DataContext.HoofdgroepIndustries.Include("SubgroepIndustries")
doesnt work
ObjectContext is a class that is generated inside the generated DomainService class that you made.
Just do a this.ObjectContext in the DomainService class you made and you should have access to the class you are looking for.
I have assumed here that you are using RIA services and your DomainService MetaData class is tagged with [Include] attributes. Otherwise doing this.ObjectContext.SomeEntity.Include("ChildEntity") will not work out.
Edit:
Add <IncludeAttribute()> _ to Public Property SubgroepIndustries As EntitySet(Of SubgroepIndustrie) in your .metadata.vb
As for ObjectContext, looking at your code you don't need ObjectContext I think. Use DataContext instead.
so for example:
Public Function GetHoofdgroepIndustries() As IQueryable(Of HoofdgroepIndustrie)
Return Me.DataContext.HoofdgroepIndustries.Include("SubgroepIndustries")
End Function
is how you will do it.
Edit 2: You need Imports System.ServiceModel.DomainServices.Server for <IncludeAttribute()>