HQL to insert entity references by passing property values? - c#

I'm having problems sorting through all the Google results for my search terms; too much information that is close but not what I'm looking for, so... off to StackOverflow!
I have three tables, Stocks, StockProperties, and StockPropertyTypes.
One Stock record has zero or more StockProperties associated with it, and has a unique column symbol. Each StockProperty record has exactly one reference to a StockPropertyType, and exactly one reference to a Stock. The StockPropertyTypes table has a unique column code. The entities for these tables do not have the FK id's for the references, just the classes. For example, the StockProperty entity looks like:
public class StockProperty
{
public virtual Guid StockPropertyId { get; set; }
public virtual Stock Stock { get; set; }
public virtual string PropertyValue { get; set; }
public virtual StockPropertyType Type { get; set; }
}
I want to pass into a method a stock symbol, a type code, and a value, and create a StockProperty record using HQL, but I'm not sure how to write that query. The Stocks table and the StockPropertyTypes have no relation. Seems like this should be some nested HQL query, but I'm not sure how to differentiate between a property and a referenced entity.
Can someone educate me what that HQL query should look like?
I should add, my goal here is to do this with one db trip; I don't want to load the Stock and StockPropertyType entities before creating the StockProperty record.

The typical way to do this is to load the Stock and StockPropertyType from the ISession. Then create a StockProperty to save using ISession.Save().
As you mention, this requires a few extra trips to the DB. One way to avoid this is to execute SQL directly as follows:
session
.CreateSQLQuery(#"insert
into StockProperty(StockSymbol, Value, TypeCode)
values (:stockSymbol, :value, :typeCode)")
.SetProperty("stockSymbol", stockSymbol)
.SetProperty("value", value)
.SetProperty("typeCode", typeCode)
.ExecuteUpdate();
You are kind of bypassing NHibernate here, but it is more efficient.
Personally, I would consider loading the related entities into memory unless you are experiencing a bottleneck. You can load both the Stock and StockPropertyType in a single DB call by using the Future<T>() paradigm.
Alternatively...
You could try fiddling with <sql-insert> inside of your hibernate mapping file. This allows you more control over how the insert is generated. You might want to add some properties StockId and StockPropertyTypeId that are only used during insert.

Related

Map C# complex data type in mongo

I have the following class hierarchy
public class Beneficiary
{
public string Id { get; set; }
public string Name { get; set; }
public InvoiceNumber InvoiceNumber { get; set; }
public ICollection<Invoice> Invoices { get; set; }
}
public class InvoiceNumber
{
public string Current { get; set; }
public DateTime IssueDate { get; }
}
public class Invoice
{
public string Number { get; set; }
public DateTime IssueDate { get; }
public ICollection<InvoiceEntry> InvoiceEntries { get; set; }
}
public class InvoiceEntry
{
public decimal BillableHours { get; set; }
}
Up till now I've used EF to configure relations but I would like to move to mongo (this is just for learning purposes).
In entity frameowrk I know how to map this type of hierarchy, but i don't know in mongo.
As it is seen only Beneficiary has an Id attached and generated but the rest is just a dependent hierarchy, so if the beneficiary gets deleted everything else will get deleted.
Can I map such class structure in mongo ? I'm using fluent api for mapping
BsonClassMap.RegisterClassMap<Beneficiary>(type =>
{
type.MapIdProperty(prop => prop.Id)
.SetIdGenerator(new StringObjectIdGenerator())
.SetSerializer(new StringSerializer(BsonType.ObjectId));
type.MapProperty(prop => prop.Name)
.SetIsRequired(true);
});
but I'm stuck because I don't know how to continue mapping the complex data types.
TLDR; After having decided on the document structure, you add maps for the classes if you want to customize the way they are serialized as you did for Beneficiary. For the most part, the defaults work well and the driver will (de)serialize your class structure to a document just fine.
If your data model is more complicated, you will have several document types; relationships are not depicted using navigation properties like in Entity Framework, but need dedicated query and update statements.
Before mapping the data, you should decide how to model the data. In this regard, MongoDB offers more options than the relational "normalize-everthing" approach. When it comes to relationships between data types, the following factors come into play:
Which type of relationship is it? 1:1 as in Beneficiary <-> InvoiceNumber, 1:n (where n is a few) or 1:z (where z means a lot like zillions)? As regards the relationship Beneficiary <-> Invoices you have to check which of the latter is the case for most of the documents. Including a few invoices in Beneficiary is ok, but storing a huge number of invoices means putting them in a separate collection (or documents at least).
Do you query the data together? If you query all the data together in most of the cases, putting all of them in a single document is an option; if you do not query them together or query only a subset of invoices (e.g. the last ten), you can have a look at the Subset pattern where Beneficiary stores only the latest invoices and the others are put into a separate collection.
If you load a Beneficiary, do you need all data for the invoices or only a part of it? If for instance you want to show the Beneficiary with an overview of the latest ten invoices, you could opt for a combination of the Subset and Extended reference patterns. This means you store Invoices in a separate collection, but include the most important data (e.g. id, number, date, totals) in the Beneficiary document to be able to fill the overview from a single document.
Are there exceptions to the amount of invoices of a Beneficiary? Do most Beneficiaries have 10 invoices, but a few have several thousand? In this case have a look at the Outlier pattern that prepares your documents to store invoices in the Beneficiary document, but adds a flag that signals that more invoices can be found in a different collection.
How often do you update the documents? Do you need to update Beneficiary every time you add an invoice?
How important are atomic updates to you? If all of the data are in a single document, all updates to this document are atomic whereas you need transactions if consistency is as important as it is in the relational world. I could imagine that InvoiceNumber is updated every time an Invoice is created and that consistency matters in this aspect.
Another option is to put Beneficiary and Invoices in separate documents in the same collection. You discern between the document types with a type discriminator (usually the _t property) but you have the advantage to be able to load both the Beneficiary and the corresponding Invoices with a single statement.
After having decided on the structure, mapping the data is usually not too complicated. In comparison to Entity Framework, you do not have to use navigation properties, but only create properties for the classes that are contained in your Beneficiary document. If your class contains subdocuments (like Beneficiary.InvoiceNumber), the driver will store the value as a subdocument. Also, in your current structure, if you have a collection like Beneficiary.Invoices, the driver will create an array when storing the data. Vice versa, when loading a Beneficiary, the properties will be deserialized from the BSON document, so Beneficiary.InvoiceNumber will contain an object of type InvoiceNumber (unless it is null) and Beneficiary.Invoices will contain a collection of Invoice objects, respectively.
If you want to customize the way that the other classes are serialized, you create another mapping as you already did for Beneficiary.
However, if you decide to store invoices in separate documents, you do not have the same comfort as in Entity Framework when loading the data (e.g. Include), but have to create separate query and update statement for Invoices (maybe with transactions if - and only if - required).

A correct way to alter Cassandra table via C#

My issue is in the next.
I have the next simple model in my code:
public class Client
{
public Guid Id { get; set; }
public string Name { get; set; }
}
I defined a mapping for it:
public class CustomMappings : Mappings
{
public CustomMappings()
{
For<Client>().TableName("clients")
.PartitionKey(x => x.Id);
}
}
I created the table via Table<TEntity>.CreateIfNotExist() method:
var table = new Table<Client>(session);
table.CreateIfNotExists();
And I can insert my data by the next way:
IMapper mapper = new Mapper(session);
var client = new Client
{
Id = Guid.NewGuid(),
Name = "John Smith"
};
await mapper.UpdateAsync(client);
After this, I've changed my model by adding a new property:
public class Client
{
public Guid Id { get; set; }
public string Name { get; set; }
public string Surname { get; set; }
}
I need to alter this table, because I want to add surname column to it.
Of course, I have the exception without it when I try to insert a value:
Cassandra.InvalidQueryException: Undefined column name surname
at Cassandra.Requests.PrepareHandler.Prepare(PrepareRequest request, IInternalSession session, Dictionary`2 triedHosts)
at Cassandra.Requests.PrepareHandler.Prepare(IInternalSession session, Serializer serializer, PrepareRequest request)
at Cassandra.Session.PrepareAsync(String query, IDictionary`2 customPayload)
at Cassandra.Mapping.Statements.StatementFactory.GetStatementAsync(ISession session, Cql cql, Nullable`1 forceNoPrepare)
at Cassandra.Mapping.Mapper.ExecuteAsync(Cql cql)
But class Cassandra.Data.Linq.Table<TEntity> does not contain neither nor .AlterOrCreate() nor .Alter() methods. Also, we don't have .GetAlter() method in Cassandra.Mapping.Statements.CqlGenerator.
Which way is more appropriate to solve this problem? I have two assumptions (besides creating a pull request with needed methods to datastax csharp driver repository on github :)).
To alter tables via cql script in .cql file which will be executed in c# code.
To create a new table after each changes of a model and migrate old data to it.
I'm a newbee in Cassandra and I have suspicions that needed method does not exist in the library for good reason. Maybe, are there any problems with consistency after altering because Cassandra is distributed database?
Changes in the Cassandra's schema should be done very accurately - you're correct about distributed nature of it, and when making changes you need to take into account. Usually it's recommended to make changes via only one node, and after execution of any DDL statement (create/drop/alter) you need to check for schema agreement (for example, via method CheckSchemaAgreementAsync of Metadata class), and don't execute next statement until schema is in agreement.
Talking about changes themselves - I'm not sure that C# driver is able to automatically generate the changes for schema, but you can execute the changes as CQL commands, as described in documentation (please read carefully about limitations!). The changes in schema could be separated into 2 groups:
That could be applied to table without need to migrate the data
That will require creation of new table with desired structure, and migration of data.
In the first group we can do following (maybe not a full list):
Add a new regular column to table
Drop a regular column from table
Rename the clustering column
Second group includes everything else:
Changing the primary key - adding or removing columns to/from it
Renaming of non-clustering columns
Changing the type of the column (it's really recommended to create completely new column with required type, copy data, and then drop original column - it's not recommended to use the same name with different type, as it could make your data inaccessible)
Data migration could be done by different tools, and it may depend on the specific requirements, like, type change, etc. But it's a different story.

Bindable indexed in-Memory Data Scturcture

I want to improve one of my current applications that uses ADO Data Sets. The application is standalone, no DBs. Almost everyone says that ADO Data set is an old stuff and a much better approach is using your own structures. For example I have the data model below (the same kind of model we usually use with Entity Framework):
public class Customer
{
public int ID {get;set;}
public string Value {get;set}
public IEnumerable<Order> Orders {get;set;}
}
public class Order
{
public int ID {get;set;}
public string Value {get;set}
public Customer Customer {get;set;}
}
I don't understand the next:
How to store class model in memory. Just in a simple List<>. It is not efficient with searching. In SQL we can make indexes for two often used columns and optimize our search. Can we do something similar (fast indexed search by multiple columns) in memory? If can, please explain me how. In DataTables we can use Primary Key as index.
Is a good data structure exist. A structure that allows binding to DataGrids, Fast indexed search by multiple columns, LINQ. Or we need to store everything in List<> or Hashset<> and prepare some additional structures for fast searching.

Map queries to multiples entities with Database First EF5 and view them in a DataGrid

I'm doing my first steps with Database First EF5 and I'm trying to reproduce my knowledge from the classical DataTable, DataAdapter, etc.. in EF5 ORM paradigm but I'm stuck:
I use to work a lot with DataGridsViews and Trees and fill them with Stored Procedures. The information that I use to display correspond with more than 1 table/entity.
For example, supposing a blog app. with posts, users, etc. like this:
Tables:
Post {Id, Subject, Body, Date, Author}
User {Id, Name, Email, Pwd}
And for joining all the tables and calculating some values we have an StoredProcedure. This SP returns attributes from Post and User tables and 2 run-time calculated values:
Post.Subject, Post.Body, Post.Categories, User.Name, DaysSincePublished, IsAuthorOnline
Or to make it easier:
Post.*, User.*, DaysSincePublished, IsAuthorOnline
Questions:
Is it possible to fit the previous record set in a multiples entities at once (Post and User)? And fill with it a DataGridView?
Is it possible to fit it in a entity created on-the-fly? And in that case is it possible to update (bind) it form the DataGridView.
Am I doing a wrong approach to the problem?
I have tried methods like Context.ObjectContext.Translate<TEntity>() or Context.Database.SqlQuery<TEntity>(storedProcedure, parameterArray); but only returns 1 entity at time.
Note:
With this example is it possible to forget about the StoredProcedure and make a linq query. But in the real scenario I have queries with more than 10 tables, and sub-queries, few times without FK, ... and caring a lot about server performance the stored procedure is a Must.
Well, your question is quite vague, anyway...
To use correctly an ORM, like EF, I think it's a good thing to understand as well SQL world than object world.
So, let's say you have two classes corresponding to your tables :
I imagine that you will use Database first, not Code First or Model First.
When using EF, classes will be generated from your db.
something like that :
public partial class Post {
public int Id {get;set;}
public string Subject {get;set;}
public string Body {get;set;}
public DateTime Date {get;set;}
//etc.
public virtual User Author {get;set;} //this is what's called a Navigation proeprty, which will help you to find relations with your User class.
}
public partial class User {
public int Id {get;set;}
public string Name {get;set;
public IList<Post> Posts {get;set;}//Navigation property from User to Post class. It's a list, reflecting the one-to-many from Post to User.
}
Now, for calculated properties, you can do this in a few ways.
One would be to create another part of the partial class Post
public partial class Post {
public int DaysSincePublished {get {return (DateTime.Now - Date).Days;}}
}
Then, you can use a simple query like that, saying you have
public DbSet<User> Users {get;set;}
public DbSet<Post> Posts {get;set;}
Then
var myQuery = context.Users.Include(m => m.Posts);
var list = myQuery.ToList();//this will get data from your db.
in list, you've got all the fields you need, including the "calculated properties" (well, you've got all from Post and User, which maybe more than what you really need, in fact).
To avoid retrieving all, you may use select data in an anonymous type (or a custom class)
var myQuery = context.Posts.Select(m => new {
subject = m.Subject,
body = m.Body,
userName = m.User.Name,
daysSincePublished = SqlFunctions.DiffDays(m.Date, DateTime.Now)//see another way to get calculated value
});
var list = myQuery.ToList()//retrieving only the required fields from db.
And the argument of "my real needs are too complicated for an ORM" doesn't make that much sense. Anyway, you will still be able to use SP when needed, or even raw sql. The goal is too be pragmatic, but investigate a little bit before coming to a definitive conclusion;)

edmx mapping questions

I have a Branch table that contains:
company_id, is_deleted, branch_id, branch_name, branch_code
company_id - used in order to determine which company owns the branch.
is_deleted - rows where is_deleted=true are logically deleted and I don't want to return them in my queries.
I have to map thos fields to class Branch. Class Branch have the following members:
BranchId, BranchName, BranchCode
Should I add IsDeleted member in order to map the is_deleted field? Can I filter rows with is_deleted=true if I will not map this field?
Should I add CompanyId member in order to map the company_id field? I have many tables with company_id field since it decide whice company own the row. Can I prevent adding CompanyId member when mapping those tables? When inserting, I need to supply CompanyId - I really prefer to supply it externaly and not from the Branch object.
So now you have a concrete example so we can continue in discussion from your previous question where I described some basic information about mapping to existing objects.
Should I add IsDeleted member in order
to map the is_deleted field? Can I
filter rows with is_deleted=true if I
will not map this field?
It is possible. It's called conditional mapping where your is_delete column will be used as a filter in the mapping. It has pros and cons:
Pros:
The filter is applied every time you query the entity set including a lazy loading and an eager loading. You will never get an entity with is_deleted = 1.
Cons:
You can't map is_deleted as a property in the entity. This is one global disadvantage for all columns used to support conditional mapping, table per hierarchy inheritance and independent associations - they can't be exposed as properties. So how would you soft delete your entity if you don't have the column exposed and you can't set it in the application? The only solution for this is stored procedure mapped to delete operation for your entity - btw. it is probably the best solution if you want to do soft / logical deletes because otherwise accidental call of DeleteObject on the context or a set will do hard delete in the database.
You can't map multiple conditional entities to the same table. It means you can't have conditionally mapped both undeleted and deleted entity. This can be handled by table per hierarchy inheritance.
Btw. as I know this is not available in DbContext API (EF 4.1).
Should I add CompanyId member in order
to map the company_id field? I have
many tables with company_id field
since it decide which company own the
row. Can I prevent adding CompanyId
member when mapping those tables? When
inserting, I need to supply CompanyId
- I really prefer to supply it externaly and not from the Branch
object.
Do you have a relation between the company table and the branch table in your database? In such case your Branch entity must use either independent or foreign key association with the Company entity. Association by default creates navigation property on both related entities so your Company entity will have collection of related Branches and your Branch will have a reference to the Company it belongs to. Navigation properties are the main way how to create relations in the object world. So if you want the Branch to belong to any Company you will either assign the Company to the property in the Branch or add the Branch to the collection of branches in the Company. That is the theory - it is little bit more complex with EF when using detached objects.
To avoid some problems EFv4 introduced foreign key association where dependent entity doesn't have only navigation property but also foreign key property (your country_id). You can create relation simply by assigning this property with the id of related Country.
I have already answered separate question describing differences between Independent and Foreign key associations.
Conclusion: You must use either navigation property or foreign key property to create relation between object - both these artifacts are mapped in the entity.
Now example which will also show some details you asked me yesterday. This example shows following features:
Conditional mapping (When is_deleted = 0 in mapping details)
Independent association (I have also already described how to change Independent association to Foreign key association). If you are creating the model from existing database you can check Include foreign key columns in the model in Update wizard and it will use foreign key associations instead of independent associations in the whole model.
Navigation properties on both sides of the relation
Renaming properties in conceptual model (check mapping details where nice names are mapped to database names)
Changing accessibility of the Id property setter. I already answered similar question where this was required with POCO T4 template but same must be done for custom business objects.
Support for lazy loading - check virtual keyword used in business object's code for navigation properties.
Support for tracking proxies - check virtual keyword used in business object's code for scalar properties.
Related mapped business objects will look like:
public class Branch
{
public virtual int Id { get; private set; }
public virtual string Name { get; set; }
public virtual string Code { get; set; }
public virtual Company Company { get; set; }
}
public class Company
{
public virtual int Id { get; set; }
public virtual string Name { get; set; }
public virtual ICollection<Branch> Branches { get; set; }
}
And context using these custom business objects can look like:
public class Context : ObjectContext
{
public Context()
:base ("name=ModelContainer")
{
Companies = CreateObjectSet<Company>();
Branches = CreateObjectSet<Branch>();
ContextOptions.LazyLoadingEnabled = true;
ContextOptions.ProxyCreationEnabled = true;
}
public ObjectSet<Company> Companies { get; private set; }
public ObjectSet<Branch> Branches { get; private set; }
}
No, you're going to need the field visible if you want to do something like filter on it, unless you use Stored Procedures.
I don't really understand this one. Why would you NOT want company_id visible if you need to use it when inserting? It's not going to hurt anything if it's there. :)

Categories