Joining two tables with specific columns in nhibernate - nhibernate

I have two table: Customers and Products
public class Customers
{
public virtual int Id { get; set; }
public virtual string CName { get; set; }
public virtual int Age { get; set; }
public virtual string Address { get; set; }
public virtual int Salary { get; set; }
}
public class Product
{
public virtual int Id { get; set; }
public virtual string PName { get; set; }
public virtual Customers CustomerID { get; set; }
public virtual int Amount { get; set; }
}
whit this Values in DB:
------------Customer Table----------------
| id | CName | Age | Address | Salary |
------------------------------------------
| 1 | Ben | 18 | a | 1000 |
| 2 | Mark | 20 | b | 2000 |
| 3 | Ben | 18 | a | 3000 |
| 4 | Ben | 19 | c | 4000 |
| 5 | Mark | 20 | b | 5000 |
| 6 | Jane | 21 | d | 6000 |
------------Customer Table----------------
| id | PName | CustomerID_id | Amount |
------------------------------------------
| 1 | A | 1 | 5 |
| 2 | B | 2 | 10 |
| 3 | C | 1 | 15 |
| 4 | D | 2 | 20 |
| 5 | E | 2 | 25 |
| 6 | F | 6 | 30 |
| 7 | G | 6 | 40 |
When I run this query in SQL Server Management:
SELECT CName , Amount
FROM [TestNhibernate].[dbo].[Product]
Inner Join [TestNhibernate].[dbo].[Customers]
on [TestNhibernate].[dbo].[Product].[Customerid_id]
= [TestNhibernate].[dbo].[Customers].[id]
SQL result is:
-------------------
| CName | Amount |
-------------------
| Ben | 5 |
| Mark | 10 |
| Ben | 15 |
| Mark | 20 |
| Mark | 25 |
| Jane | 30 |
| Jane | 40 |
And when I run this query
SELECT CName , Sum(salary) as SumSalary, sum(amount) as SumAmount
FROM [TestNhibernate].[dbo].[Product]
Inner Join [TestNhibernate].[dbo].[Customers]
on [TestNhibernate].[dbo].[Product].[Customerid_id]
= [TestNhibernate].[dbo].[Customers].[id]
Group By Cname
results is :
----------------------------------
| CName | SumSalary | SumAmount |
----------------------------------
| Ben | 2000 | 20 |
| Jane | 12000 | 70 |
| Mark | 6000 | 55 |
----------------------------------
How can I express that in NHiberante query?
UPDATE: some attempts
I try this code
session
.QueryOver<Product>()
.JoinQueryOver<Customers>(p => p.CustomerID)
.SelectList(w => w
.Select(x => x.Amount)
.Select(z => z.CustomerID))
.List<object[]>()
this is done but when i write this code
session
.QueryOver<Product>()
.JoinQueryOver<Customers>(p => p.CustomerID)
.SelectList(w => w
.Select(x=>x.Amount)
.Select(z=>z.CustomerID.CName))
.List<object[]>()
doesn't work!

Based on the information in the question, there is some draft of the QueryOver syntax, which should help to understand. Firstly we should create some DTO, representing the result:
public class ProductDTO
{
public virtual string ClientName { get; set; }
public virtual decimal SumSalary { get; set; }
public virtual decimal SumAmount { get; set; }
}
Now, we should have business model with a bit more standard naming:
public class Product
{
...
// instead of this
//public virtual Customers CustomerID { get; set; }
// we should use
public virtual Customers Customers { get; set; }
}
Personally I would rather see Customer than Customers... but still better than CustomersID
Because our mapping here must be <many-to-one representing reference relation, not just <property - representing the value type / integer.
Now the query:
// to have access to client name
Customers client = null;
// that would be result - used for proper columns aliasing
ProductDTO dto = null;
var result = session.QueryOver<Occupation>()
.JoinQueryOver<Customers>(p => p.Customers , () => client)
.SelectList(w => w
// SUM
.SelectSum(x => x.Amount)
.WithAlias(() => dto.SumAmount)
.SelectSum(x => x.Salary)
.WithAlias(() => dto.SumSalary)
// GROUP BY
.Select(x => client.CName)
.WithAlias(() => dto.ClientName)
)
// we do have enough info to ask NHibernate for
// fully typed result - Product DTO
.TransformUsing(Transformers.AliasToBean<ProductDTO>())
.List<ProductDTO>();
That should give some idea how to do querying with NHibernate. Also, I would suggest to extend Customer with IList<Products>

Related

AspNet Core Display multiple records as one row with multiple columns in table

I'm having trouble with table view.
I want my table to look like this one
Name | Test1 | Test2 | Test3
================================
Anna | 70 | 51 | 90
================================
Jack | 56 | 77 | 82
================================
Now I have
Name | Grade | Test |
================================
Anna | 70 | Test1 |
================================
Anna | 51 | Test2 |
================================
Anna | 90 | Test3 |
================================
Jack | 56 | Test1 |
================================
Jack | 77 | Test2 |
================================
Jack | 82 | Test3 |
================================
The number of tests is dynamic.
Is there any way to do this? Couldn't find anything.
Should I create another model? Or it could be solved by editing View?
Model
public class StudentsWork
{
[Key]
public int IdStudentsWork { get; set; }
public int? Grade { get; set; }
public DateTime? Date { get; set; }
public int Student_id { get; set; }
public int Course_id { get; set; }
public int Test_id { get; set; }
[ForeignKey("Student_id")]
public Student StudentId { get; set; }
[ForeignKey("Course_id")]
public Course CourseId { get; set; }
[ForeignKey("Test_id")]
public Test TestId { get; set; }
}
Controller
public async Task<IActionResult> Group(int? id,int id_group)
{
var group = await _context.StudentsWork
.Include(p => p.StudentId)
.ThenInclude(p => p.GroupId)
.Include(p => p.CourseId)
.Include(p => p.TestId)
.Where(c => c.Course_id == id && c.StudentId.Group_id == id_group)
.ToListAsync();
return View(group);
}
Any help would be greatly appreciated.
You can group by StudentId and select a dictionary for each group to get test name and grade :
var query = db.StudentsWork.Include(p => p.StudentId)
.Include(p => p.CourseId)
.Include(p => p.TestId)
.GroupBy(c => c.StudentId)
.Select(g => new
{
StudentName=g.Key.Name,
TestGrade = g.ToDictionary(t => t.TestId.Name, t => t.Grade)
});
var result = query.ToList();

How to validate a UserProfile at the begining of a Controller to show specific data

I have a UserProfile Model as the following:
public class UserProfile
{
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int UserId { get; set; }
public string UserName { get; set; }
public string Position { get; set; }
public string Authority { get; set; }
public string Service { get; set; }
public string Area { get; set; }
public int IsWrite { get; set; }
}
the table data looks like the following:
UserID | UseName | Position | Authority | Service | Area | IsWrite
1 | Peter | HSK Manager | Svc-Ar | HSK | WA | 0
2 | Dorothy | Branch Manager| Ar | All | EA |1
3 |Mike | HSK Director | Svc | HSK | All | 0
4 | Roddel | HSK Data Entry | Svc | HSK | All | 1
5 | Susan| WA Data Entry |Ar | All | WA | 1
6 | Nancy| Facility COO | All | All | All | 0
7 | Allan | Food Branch Mananger | Svc-Ar | FSD | EA | 0
Users has many kinds of authority scope; for example: one has an authority upon a specific service, the other has an authority upon a specific area, and may a user has authority to view records upon a service and an area both. I want to make a logic for each List controller action to check the UserProfile authority and then list data considering the scope of authority for each user.
this is another model which its data depends on the authority of users called Projects:
public class Projects
{
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int ProjectID { get; set; }
public string Service { get; set; }
public string Area { get; set; }
[Required]
[DisplayName("Project Name")]
public string ProjectName { get; set; }
[Required]
[DataType(DataType.Currency)]
[DisplayName("Contract Value")]
public double ContractValue { get; set; }
[Required]
[DisplayName ("Contract Total MP")]
public int ContractMP { get; set; }
[Editable(false)]
public int UserID { get; set; }
[DataType(DataType.DateTime )]
[DisplayFormat(DataFormatString = "{0:dd/MM/yyyy}")]
public DateTime EntryDateTime { get; set; }
}
I want to put a logic in the beginning of the Projects Controller 'Index' action to validate the user's authority; if it's "Svr" it will show only the data of his service, if his authority is "Ar" it will show only data of his Area only, if his Authority is "Svr-Ar" it will show data of his Service and Area only, and if his authority is "All" it will show all data.
I tried many ways to do this, I could not, and I am new to MVC. please help me. Regards.
May be you'd better try to use roles. Then you may simply check:
if(Roles.IsUserInRole("Ar"))
{
//Show data for role Ar
}
But you may do the same with your Authority field. Just make simple method:
public string GetUserAuthority(int UserID)
{
var user = db.UserProfile.Find(id);
return user.Authority;
}
or if you use Membership:
public string GetUserAuthority()
{
var user = Membership.GetUser(User.Identity.Name);
return user.Authority;
}
Then check in Controller Action:
if(GetUserAuthority() == "Ar")
{
//Show data for role Ar
}

How does FluentNHibernate know which row to access?

There is no issue; I'm just curious as to how FluentNHibernate/NHibernate knows which rows to access.
In the following pseudocode, I have these entities:
public class User
{
public virtual int Id { get; protected set; }
public virtual IList<Friend> Friends { get; set; }
}
public class Friend
{
public virtual int Id { get; protected set; }
public virtual User User { get; set; }
public virtual String FunnyProperty { get; set; }
}
with this one-to-many relationship:
public class UserMap : ClassMap<User>
{
Id(x => x.Id);
// One user has many friends
HasMany(x => x.Friends).KeyColumn("UserId")...
}
public class FriendMap : ClassMap<Friend>
{
Id(x => x.Id);
References(x => x.User, "UserId")...
}
If I run the following code to establish the two-way relationship:
var user = new User().Friends.AddRange( /* 5 friends */ );
/* 5 friends */.ForEach(friend => friend.User = user);
and then set:
user[2].FunnyProperty = "a magic string";
then, in a visual database explorer tool, I see the table Users as:
Id
--------------------------------------
63
--------------------------------------
and the table Friends as:
Id | UserId | FunnyProperty
--------------------------------------
24 | 63 | (null)
--------------------------------------
25 | 63 | (null)
--------------------------------------
26 | 63 | a magic string
--------------------------------------
27 | 63 | (null)
--------------------------------------
28 | 63 | (null)
--------------------------------------
How does FluentNHibernate/NHibernate "remember" id 26 as the 3rd Friend object in user.Friends? Say you commit the transaction, begin another transaction elsewhere, and retrieve the same user.Friends[2]. How does FluentNHibernate/NHibernate know to access the row with id 26?
Especially when when you have a Friends table with many different Users floating about, like below, how does FluentNHibernate/NHibernate "remember" which row to access ?:
Id | UserId | FunnyProperty
--------------------------------------
24 | 24 | (null)
--------------------------------------
25 | 89 | (null)
--------------------------------------
26 | 66 | a magic string
--------------------------------------
27 | 12 | (null)
--------------------------------------
28 | 66 | (null)
--------------------------------------
28 | 89 | (null)
--------------------------------------
Your Friends table contains the property UserId which is the referenence to friends. Fluent NHibernatie reads you mapping where you have defined this.
There is also an index column in the Friends table.

Silverlight DomainDataSource in code-behind not loading all rows

I have a domain data source in Silverlight 4. I'm setting it up in the code behind, and I'm also using a RadDataPager and RadGridView.
DomainDataSource dds = new DomainDataSource();
dds.QueryName = "MyQueryName";
dds.DomainContext = ctx;
dds.LoadSize = 10;
dds.PageSize = 10;
dds.AutoLoad = true;
radDataPager1.PageSize = 10;
radDataPager1.Source = dds.Data;
radGridView1.ItemsSource = dds.Data;
dds.Load();
The first time this loads, the dds.Data.Count is 8, and only 8 items show up in the grid view, even though the dds.Data.PageSize is 10. After I page to the next page, all 10 objects are loaded like they should be.
I'm new to Silverlight, and have no idea what is going on here. Am I loading the data wrong? Any ideas?
This behavior can be caused by wrong set of Key attribute in your model class. If in the result query, rows with Key field are duplicated, then DataGrid will take only first.
Example (book store info ):
Your result class (BookPriceInfo.cs) looks like this:
public class BookPriceInfo {
[DataMember]
[Key]
public int BookId { get; set; }
[DataMember]
public string Name {get; set; }
[DataMember]
public string StoreName {get; set;}
[DataMember]
public decimal Price {get; set;}
}
And if you have query result returned from database :
BookId | Name | StoreName | Price
1 | book1 | store1 | 70.00
1 | book1 | store2 | 69.99
2 | book2 | store1 | 40.00
2 | book2 | store2 | 39.99
Then DataGrig will show only this :
BookId | Name | StoreName | Price
1 | book1 | store1 | 70.00
2 | book2 | store1 | 40.00
this happens because of DataGrid will 'distinct' the results by field marked as Key(get only first row from all rows with same BookId), because it should be uniq for all rows.
Solution
Remove Key attribute from field which will have duplicated values (BookId) and set it to field which will have uniqe values for all rows (you can add some column like BookPriceId, which will be uniqe).
public class BookPriceInfo {
[DataMember]
public int BookId { get; set; }
[DataMember]
public string Name {get; set; }
[DataMember]
public string StoreName {get; set;}
[DataMember]
public decimal Price {get; set;}
[DataMember]
[Key]
public int BookPriceId {get; set;}
}
Query result:
BookPriceId | BookId | Name | StoreName | Price
1 | 1 | book1 | store1 | 70.00
2 | 1 | book1 | store2 | 69.99
3 | 2 | book2 | store1 | 40.00
4 | 2 | book2 | store2 | 39.99
After that you should see all rows returned by query.
Hope this helps :)

Using NHibernate with an EAV data model

I'm trying to leverage NH to map to a data model that is a loose interpretation of the EAV/CR data model.
I have most of it working but am struggling with mapping the Entity.Attributes collection.
Here are the tables in question:
--------------------
| Entities |
--------------------
| EntityId PK |-|
| EntityType | |
-------------------- |
-------------
|
V
--------------------
| EntityAttributes | ------------------ ---------------------------
-------------------- | Attributes | | StringAttributes |
| EntityId PK,FK | ------------------ ---------------------------
| AttributeId FK | -> | AttributeId PK | -> | StringAttributeId PK,FK |
| AttributeValue | | AttributeType | | AttributeName |
-------------------- ------------------ ---------------------------
The AttributeValue column is implemented as an sql_variant column and I've implemented an NHibernate.UserTypes.IUserType for it.
I can create an EntityAttribute entity and persist it directly so that part of the hierarchy is working.
I'm just not sure how to map the EntityAttributes collection to the Entity entity.
Note the EntityAttributes table could (and does) contain multiple rows for a given EntityId/AttributeId combination:
EntityId AttributeId AttributeValue
-------- ----------- --------------
1 1 Blue
1 1 Green
StringAttributes row looks like this for this example:
StringAttributeId AttributeName
----------------- --------------
1 FavoriteColor
How can I effectively map this data model to my Entity domain such that Entity.Attributes("FavoriteColors") returns a collection of favorite colors? Typed as System.String?
here goes
class Entity
{
public virtual int Id { get; set; }
internal protected virtual ICollection<EntityAttribute> AttributesInternal { get; set; }
public IEnumerable<T> Attributes<T>(string attributeName)
{
return AttributesInternal
.Where(x => x.Attribute.Name == attributeName)
.Select(x => x.Value)
.Cast<T>();
}
}
class EntityAttribute
{
public virtual Attribute Attribute { get; set; }
public virtual object Value { get; set; }
}
class EntityMap : ClassMap<Entity>
{
public EntityMap()
{
HasMany(e => e.AttributesInternal)
.Table("EntityAttributes")
.KeyColumn("EntityId")
// EntityAttribute cant be an Entity because there is no real Primary Key
// (EntityId, [AttributeId] is not unique)
.Component(c =>
{
c.References(ea => ea.Attribute, "AttributeId").Not.LazyLoad();
c.Map(ea => ea.Value, "AttributeValue").CustomType<VariantUserType>();
});
}
}