I have a table 'Article'
private int id;
[ColumnAttribute(Storage = "id", AutoSync = AutoSync.OnInsert, DbType = "Int NOT NULL IDENTITY", IsPrimaryKey = true, IsDbGenerated = true)]
public int Id
{
get { return id; }
set { id = value; }
}
private string title;
[ColumnAttribute(Storage = "title", DbType = "NVarChar(250) NOT NULL", CanBeNull = false)]
public string Title
{
get { return title; }
set { title = value; }
}
private string description;
[ColumnAttribute(Storage = "description", DbType = "NVarChar(350) NOT NULL", CanBeNull = false)]
public string Description
{
get { return description; }
set { description = value; }
}
and a table comment
[Table(Name = "dbo.Comments")]
public class CommentDto
{
private int id;
[ColumnAttribute(Storage = "id", AutoSync = AutoSync.OnInsert, DbType = "Int NOT NULL IDENTITY", IsPrimaryKey = true, IsDbGenerated = true)]
public int Id
{
get { return id; }
set { id = value; }
}
private string content;
[ColumnAttribute(Storage = "content", DbType = "NVarChar(600) NOT NULL", CanBeNull = false)]
public string Content
{
get { return content; }
set { content = value; }
}
private string date;
[ColumnAttribute(Storage = "date", DbType = "DateTime NOT NULL", CanBeNull = false)]
public string Date
{
get { return date; }
set { date = value; }
}
}
One Article can have many comments and each comment can be placed by a User
[TableAttribute(Name = "dbo.Users")]
public class UserDto
{
private int id;
[ColumnAttribute(Storage = "id", AutoSync = AutoSync.OnInsert, DbType = "Int NOT NULL IDENTITY", IsPrimaryKey = true, IsDbGenerated = true)]
public int Id
{
get { return id; }
set { id = value; }
}
private string username;
[ColumnAttribute(Storage = "username", DbType = "NVarChar(150) NOT NULL", CanBeNull = false)]
public string Username
{
get { return username; }
set { username = value; }
}
How do I map the relatinship between these tables?
Thanks
I think you are creating your table classes manually. there is no need to do that.
add a LINQ to SQL (dbml) file to your solution, open Server Explorer window and connect to your database,
drag and drop the tables into the design of your dbml class.
if there are foreign key constraints in your tables, then link will create respective properties in both classes.
and if you want to do it manually (which I can't see why),
create a property with the type of the referenced class and this is the attribute needed:
[Association(Name="your_fk_constraint_name", Storage="name_of_your_private_backup_field", ThisKey="name_of_the_key_in_this_table", IsForeignKey=true)]
hope I helped a little
You can read about mapping associations here.
In your case:
class Article
{
private EntitySet<CommentDto> _Comments;
[Association(OtherKey = "ArticleID")]
public virtual IList<CommentDto> Comments
{
get
{
if (_Comments == null)
_Comments = new EntitySet<CommentDto>();
return _Comments;
}
set
{
Comments.Assign(value);
}
}
}
class Comment
{
[Association(ThisKey="ArticleID")]
public ArticleDto Article { get; set; }
}
Of course, you should first add ArticleID column to Comments table in database.
The part below is not presented in MSDN code from the link above, but without it I had a lot of problems with DTO in WCF service. So, now I prefer to add it to every association:
if (_Comments == null)
_Comments = new EntitySet<CommentDto>();
Related
as the question title says, I am trying to map a custom object to a db column on windows phone how can I do this? the exception I am getting: "Unable to determine SQL type for 'Layer'."
layer is a custom object, what is the correct way to store this, can someone please provide me with a example. thank you
code:
...
[Table]
public class Product : INotifyPropertyChanged, INotifyPropertyChanging
{
#region ID
//not autogenerated, this is from the client
private String _id;
[Column(IsPrimaryKey = true, IsDbGenerated = false, DbType = "INT NOT NULL Identity", CanBeNull = false, AutoSync = AutoSync.OnInsert)]
public String Id
{
get { return _id; }
set
{
if (_id != value)
{
NotifyPropertyChanging("id");
_id = value;
NotifyPropertyChanged("id");
}
}
}
#endregion
#region Product Layer
private Layer _productlayer;
[Column]
public Layer ProductLayer
{
get { return _productlayer; }
set
{
if (_productlayer != value)
{
NotifyPropertyChanging("ProductLayer");
_productlayer = value;
NotifyPropertyChanged("ProductLayer");
}
}
}
#endregion
....
public class Layer
{
public string name{ get; set; }
public string des { get; set; }
public string pos { get; set; }
}
I'm trying to create an app just for learing purposes.
I'd Like to dynamically save any object to the right context.
So my idea is something like this:
My businessmodel for the player is this:
[Table]
public class PLAYER:ISiedlerEntity
{
[Column(CanBeNull = false, IsPrimaryKey = true, DbType = "INT NOT NULL Identity", IsDbGenerated = true, AutoSync = AutoSync.OnInsert)]
public long ID { get; set; }
[Column]
public string Name { get; set; }
[Column]
public int GamesPlayed { get; set; }
}
}
The context is this:
public class PLAYERS:DataContext
{
private const string CONNECTION_STRING = "isostore:/tblPLAYERs.sdf";
public Table<PLAYER> Entities;
public PLAYERS()
: base(CONNECTION_STRING)
{
}
}
Do you think there is a possibility to handle the saving in one function just by passing the ISiedlerEntitiy?
My approach so far:
public static bool Save(ISiedlerEntity entity)
{
bool result = true;
string dcName = entity.GetType().Name + "S";
PropertyInfo pi = CurrentApp.GetType().GetProperty(dcName);
DataContext dc = pi.GetValue(CurrentApp) as DataContext;
foreach (var prop in dc.GetType().GetProperties())
{
if (prop.Name == "Entities")
{
var t = prop.GetValue(dc);
}
}
return result;
}
So far so fine, but now I need to cast the datacontext to the specified context, to access the Entities property.
Do you think this is possible so far? Or is there a easier solution?
Thanks and a good evening to everybody.
Matthias Müller
I'm writing a wpf app. I have a local database (sqlCE) with two entity classes that correspond to different tables. The first one class is Account and the second one is Movements. There's a relationship one-to-many between the two tables: an account can have more movements.
Here is Account class:
[Table]
public class Account
{
.....other private fields...
private Int16 iDA;
private EntitySet<Movement> movements;
...other properties with column attribute....
//primary key
[Column(IsPrimaryKey = true, Storage="iDA", IsDbGenerated = true, AutoSync = AutoSync.OnInsert, DbType = "smallint")]
public Int16 IDA
{
get { return iDA; }
private set { iDA = value; }
}
//association
[Association(Storage = "movements", OtherKey = "IDA")]
public EntitySet<Movement> Movements
{
get { return movements; }
set { this.movements.Assign(value); }
}
public Account()
{
this.movements = new EntitySet<Movement>();
}
}
and here's Movement class:
[Table]
public class Movement
{
...other fields...
private Int16 iDA;
private int iDM;
private EntityRef<Account> myAcc;
//primary key
[Column(IsPrimaryKey = true, IsDbGenerated = true, AutoSync = AutoSync.OnInsert, DbType = "int NOT NULL IDENTITY", Storage = "iDM")]
public int IDM
{
get { return iDM; }
set { iDM = value; }
}
//property links the two tables
[Column(DbType = "smallint", Storage="iDA", isPrimaryKey=true)]
public Int16 IDA
{
get { return iDA; }
set { iDA = value; }
}
//association
[Association(Storage = "myAcc", ThisKey = "IDA")]
public Account MyAccount
{
get { return this.myAcc.Entity; }
set { this.myAcc.Entity = value; }
}
......
public Movement()
{
this.myAcc = new EntityRef<Account>();
}
}
I define IDA property to link the two tables. After that I write datacontext class:
public class DataBase : DataContext
{
public Table<Account> AccountTable
{
get { return this.GetTable<Account>(); }
}
public Table<Movement> MovementTable
{
get { return this.GetTable<Movement>(); }
}
public DataBase(string connection) : base(connection) { }
}
In mainclass I create database, but when i try to populate it with an account object, I get a sql exception! I can insert data calling InsertOnSubmit(Account a) without problems, but when I call SubmitChanges() the program stops and the exception says "The column can not contain null values. [Column name = IDA, Table name = Account]".
Anyone can help me?
Try using DbType = "smallint not null identity" and CanBeNull = false parameters for the Column attribute of the IDA field.
I've solved my problem, changing in Int the IDA property in both classes and making some adjustment.
I have simple mapping:
[Table(Name="Person")]
public class Person
{
private int id;
private int state_id;
private EntityRef<PersonState> state = new EntityRef<PersonState>();
[Column(IsPrimaryKey = true, Storage = "id", Name="id",
IsDbGenerated = true, CanBeNull = false)]
public int ID
{
get { return id; }
set { id = value; }
}
[Column(Storage="state_id", Name="state_id")]
public int StateID
{
get{ return state_id;}
set{ state_id = value;}
}
[Association( Storage = "state", ThisKey = "StateID", IsForeignKey=true)]
public PersonState State
{
get { return state.Entity; }
set { state.Entity = value; }
}
}
[Table(Name = "PersonState")]
public class PersonState
{
private int id;
private State state;
[Column(Name="id", Storage="id", IsDbGenerated=true, IsPrimaryKey=true)]
public int ID
{
get { return id; }
set { id = value; }
}
[Column(Name = "date", Storage = "date")]
public DateTime Date
{
get { return date; }
set { date = value; }
}
[Column(Name = "type", Storage = "state")]
public State State
{
get { return state; }
set { state = value; }
}
}
I use this code to insert new person with default state:
private static Person NewPerson()
{
Person p = new Person();
p.State = DefaultState(p);
return p;
}
private static PersonState DefaultState()
{
PersonState state = new PersonState();
state.Date = DateTime.Now;
state.State = State.NotNotified;
state.Comment = "Default State!";
return state;
}
Leater in code:
db.Persons.InsertOnSubmit(NewPerson());
db.SubmitChanges();
In database(sqlite) I have all new persons, but state_id of all persons is set to 0, and PersonState table is empty. Why Linq did not insert any State object to database?
It's because you aren't telling it to insert the changes to the PersonState table. I would think that having your entities linked together would make this happen automatically but you may have to trying something like this:
Person p = NewPerson();
db.Person.InsertOnSubmit(p);
if (p.State != null)
{
db.PersonState.InsertOnSubmit(p.State);
}
db.SubmitChanges();
maybe someone can help.
I want to have on mapped Linq-Class different Datatype.
This is working:
private System.Nullable<short> _deleted = 1;
[Column(Storage = "_deleted", Name = "deleted", DbType = "SmallInt", CanBeNull = true)]
public System.Nullable<short> deleted
{
get
{
return this._deleted;
}
set
{
this._deleted = value;
}
}
Sure thing. But no when i want to place some logic for boolean, like this:
private System.Nullable<short> _deleted = 1;
[Column(Storage = "_deleted", Name = "deleted", DbType = "SmallInt", CanBeNull = true)]
public bool deleted
{
get
{
if (this._deleted == 1)
{
return true;
}
return false;
}
set
{
if(value == true)
{
this._deleted = (short)1;
}else
{
this._deleted = (short)0;
}
}
}
I get always runtime error:
[TypeLoadException: GenericArguments[2], "System.Nullable`1[System.Int16]", on 'System.Data.Linq.Mapping.PropertyAccessor+Accessor`3[T,V,V2]' violates the constraint of type parameter 'V2'.]
I can't change the database to bit.. I need to have casting in mapping class.
** Update
According to mmcteam, casting in unmapped method does the trick.
Not so sure if it is ment to be using the OR Mapping that way, but it works.
private System.Nullable<short> _deleted = 1;
public bool deleted
{
get
{
if (this._deleted == 0)
{
return false;
}
else
{
return true;
}
}
set
{
if (value)
{
this._deleted = 1;
}
else
{
this._deleted = 0;
}
}
}
[Column(Storage = "_deleted", Name = "deleted", DbType = "SmallInt", CanBeNull = true)]
private short? deleted_smallint
{
get
{
return this._deleted;
}
set
{
this._deleted = value;
}
}
** NOTICE/PROBLEM
You can't use the not mapped methods on linq queries!
var result = from p in dc.Products
where p.enabled && !p.deleted
select p;
causes not supported sql exception. Without the where condition, data comes out with correct values.
Or just add one more property to your row class and cast previous one to bool.
Don't you want this:
[Column(Storage = "_deleted", Name = "deleted", DbType = "Bit", CanBeNull = false)]
public bool deleted ...
Instead of this:
[Column(Storage = "_deleted", Name = "deleted", DbType = "SmallInt", CanBeNull = true)]
public bool deleted ...
?