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.
Related
I want to do some changes in a table that is already exist(i am using sqlite). I want to remove a Attribute of a property in a class. Remove [Required] attribute. How can i do that, what should i change, should i some changes in DbContext or migration folder or what commands can i use in package manager console.
public class Appointment
{
[Required]
[MaxLength(50)]
public string Company { get; set; }
This is a good example of why it is better to use fluent API then attributes to specify your database: you want the same class to be used in a different database.
The DbContext defines the database: what tables are in it, how do the tables relate towards each other, what classes do represent the tables, and what are the constraints to the tables.
For instance, maybe in one database you want Company to have a MaxLength of 50 characters, in another database you might desire a length of 100 characters. Some databases need a simple DateTime, others require a DateTime2. Or maybe you want a different precision for your decimals?
Hence it is usually better to specify the database statistics where it belongs: in the definition of the database, which is the DbContext.
Back to your question
It depends a bit on the entity framework that you are using on how the database reacts if during migration you use remove the Required attribute and move it to fluent API. I guess it is best to experiment with it.
In OnModelCreating, or the migration equivalent of it, you will have something like:
var entityAppointment = modelBuilder.Entity<Appointment>();
var propertyCompany = entityAppointment.Property(appointment => appointment.Company);
propertyCompany.IsOptional()
.HasMaxLength(50)
...; // other non-default specifications of Company
// like columnName, IsUnicode, etc
When migrating the statements might be little different, but I guess you get the gist.
Using : dotnet core 1.1, entity framework code first, sql server.
Is there any elegant way to enable a user working on a large form, represented by a complexe model (40+ tables/C# objects), having multiple "required" fields, to save it's work temporarily and come back to complete it afterward?
Let's say I have this model :
[Table("IdentificationInfo", Schema = "Meta")]
public class IdentificationInfo : PocoBase
{
[...]
public int MetaDataId { get; set; }
[ForeignKey("MetaDataId")]
public virtual MetaData MetaData { get; set; }
public int ProgressId { get; set; }
[ForeignKey("ProgressId")]
public Progress Progress { get; set; }
public virtual MaintenanceInfo MaintenanceInfo { get; set; }
public int PresentationFormId { get; set; }
[ForeignKey("PresentationFormId")]
public PresentationForm PresentationForm { get; set; }
private string _abstract;
[Required]
public string Abstract
{
get { return _abstract; }
set { SetFieldValue(ref _abstract, value, "Abstract"); }
}
[...]
}
[Table("PresentationForm", Schema = "Meta")]
public class PresentationForm : PocoEnumeration
{
[...]
}
The user starts to fill everything (in a big form with multiples tabs or really long page!), but needs to stop and save the progress without having the time to save to fill the PresentationForm part, nor the abstract. Normally, in the database, those fields are not null, so it would fail when we try to save the model. Similarly, it would also fail with EF validation in the UI.
What would be nice is using the Progress property and disable EF model validation (model.isValid()), and also enable database insert even if the fields are null (it is not possible to put default values in those not nullable fields as they are often foreign keys to enum like table).
For the model validation part, I know we can make some custom validator, with custom annotation such as [RequiredIf("FieldName","Value","Message")]. I'm really curious about some method to do something similar in the database?
Would the easy way to do that be to save the model as JSON in a temporary table as long as the progress status is not completed, retrieve it when needed for edition directly from the JSON, and save it to the database only when the status is completed?
To support (elegantly) what you ask you should design it that way.
One table with it's required columns should be minimum segment that have to be inputted before any save. Should make segment optimal size.
You could set all fields to allow null but that would be very BAD design, so I would not consider that option at all.
Now if your input consist of several logical parts, and on form they could be different tabs so each tab is in one table in Db and main table have FKs of others tables.
That FK could be Nullable, and it would enable you to finish say first 2 tabs, Save it, and leave rest for after. So you will know that those FK column that have values are finished(and maybe could be edited still), while others are yet to be inserted. You can also have column Status:Draft/Active/...
What's more this design would allow you to have configurable tabs, so for example based on some chosen selection on main input you could chose what tables can be inputted, and which not and to enable/disable appropriate tabs.
If however you don't want FKs nullable than solution would be some temporary storage, one option being JSON in one string column, as you have mentioned your self. But I see no issues with nullable FKs in this case.
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.
We have a software suite with different components and a sql server database that is used by most of these components.
Let's say we have a table Configuration with two columns [Name]and [Value]. This table contains our db scheme version (as Name='Version', Value='1.0').
Then we have a table Customer with columns ID and Name.
So the class for linq-to-sql queries on this table would look something like that:
[Table(Name="Customer")]
public class Customer
{
[Column]
public long ID {get; private set;}
[Column]
public string Name {get; set; }
}
For our next release version, we need to change this Customer table and add a column Address. When we install this new scheme, we set the version value in the Configuration table to 1.1, so we can determine which version is installed.
A lot of our customers are waiting for this new version of the component because of a bugfix, but they don't actually need the new db schema (the reasons don't matter here, let's just assume our software needs backward compatibility to old db schema versions).
So my question is, is there any best practice technology to handle this situation?
If I add the new column to the Customer class like
[Column]
public string Address {get; set;}
I won't be able to use this class for requests to a db with the 1.0 schema (because of the SqlException for the missing column). If I create a new class (derived, or use interfaces or whatsoever), I have to deal with different types for different schema versions. And of course Table<Customer10> will never be convertible to Table<Customer11> no matter what the inheritance relation between Customer10 and Customer11 will be. So until now I did not find a way to encapsulate these problems inside my DataContext derivate in a transparent way:
public class MyDataContext : DataContext
{
public Table<Customer> Customers
{
get
{
// this won't compile, no matter how Customer10 and Customer11 are related
return version > 10
? GetTable<Customer11>()
: GetTable<Customer10>();
}
}
}
I also experimented with inheritance hierarchies and discriminators, but since the version is not a column of Customer, this does not seem to work.
I'd like to find a solution where I can use one type per table for different schemas and where removed or added columns would take default values if they are not supported in the installed db scheme.
I used EF6 Database First tools to generate C# classes for 2 tables from my database, then (as advised in the blog post that helped me through the steps to do that) copied the resulting .cs files into a new project. I made a few edits to the classes to support sensible names in my C# code. Here's a snippet of one of the classes with "LongTableName" replacing a strangely long name used in the database.
namespace RidesData
{
[Table("LongTableName")]
public partial class PhoneData
{
[Key]
[Column("LongTableNameID")]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int ID { get; set; }
[Column("LongTableNameAccountID")]
public int AccountID { get; set; }
// more fields
}
}
I am not in control of the table names, nor the fact that the many of the column names have the table name as prefixes. But the Code First ideas in EF6 should, I thought, let me use reasonable class and field names despite that. (The Database First code generator did a good job of adding code to OnModelCreating to specify that none of the columns corresponding to C# string data used Unicode.)
My model (generated by the EF6 tools and that inherits from DbContext) includes (after some renaming by me)
public virtual DbSet<PhoneData> PhoneRecs { get; set; }
and I thought all would be fine when I created an instance of PhoneData, populated it, and did
Model.PhoneRecs.Add(phoneData);
but the first thing that happened when I ran the code -- well before any call to SaveChanges() -- was that EF generated CREATE TABLE statements for the two tables; the table corresponding to the snippet above was named PhoneDatas (not using the specified table name) and the column names were the same as the field names in the class (not what was specified in the Column(...) attributes).
Of course the table I had specified did not need to be created. EF just had to grok that I wanted to use the table and column names I had specified via attributes.
I did not expect this failure of explicit Code First attributes. Does anyone have a clue why this isn't doing what I want, or how to fix it? (Do I have to do something to specify the table & column names in OnModelCreating as well as -- or instead of -- the attributes?)
Note that the project that I copied these classes into had never "seen" the database before. There are no vestiges of any "models" left over from tooling having looked at the database. Also, I hope it does not matter that I've tried to keep things on .Net 4.0 (avoiding going to 4.5 in this code).
Any assistance would be appreciated.
I'm not a big fan of DataAnotations either. Use EntityTypeConfiguration. It gives you the naming flexibility I think you are looking for.
Example.
public class PhoneData
{
public int ID {get;set;}
public string SomeProperty {get;set;}
}
public class PhoneDataMap : EntityTypeConfiguration<PhoneData>
{
public PhoneDataMap()
{
ToTable("WhatEverYou_Want_to_call_this");
HasKey(m => m.Id);
Property(m => m.SomeProperty).HasColumnName("whatever").IsRequired();
//etc.
}
}
Then in your on ModelCreating you add
modelBuilder.Configuration.Add(new PhoneDataMap());
On a side note, if you are having trouble with pluralization of your table names you can add this to OnModelCreating as well
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();