linq2sql insert data in database one-to-many relationship - c#

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.

Related

WP8 & Linq to SQL with One-to-Many relation: SubmitChanges() removes wrong entity

I have the following entites/tables:
Board: One board can have many pins
Pin: One pin is assigned to one board. This entity is abstract and does have childs with different implementations. All childs belonging to the parent pin entity with InheritanceMapping and will be saved into the pin table and distinguished by a Discriminator column
TaskPin: This is one child implementations of pin. It can have many Tasks.
Task: One task is assigned to one TaskPin
Here is some code to make my structure more clear:
[Table]
public class Board : ModelBase
{
private int _boardId;
[Column(IsPrimaryKey = true, IsDbGenerated = true, DbType = "INT NOT NULL Identity"
,CanBeNull = false, AutoSync = AutoSync.OnInsert)]
public int BoardId
{
get { return _boardId; }
set { SetProperty(ref _boardId, value); }
}
private EntitySet<Pin> _pins;
[Association(Storage = "_pins", OtherKey = "_boardId"
,ThisKey = "BoardId", DeleteRule = "CASCADE")]
public EntitySet<Pin> Pins
{
get { return _pins; }
set { _pins.Assign(value); }
}
public Board()
{
_pins = new EntitySet<Pin>(new Action<Pin>(this.addPin)
,new Action<Pin>(this.removePin));
}
private void addPin(Pin pin)
{
NotifyPropertyChanging("Pin");
pin.Board = this;
}
private void removePin(Pin pin)
{
NotifyPropertyChanging("Pin");
pin.Board = null;
}
}
[Table]
[InheritanceMapping(Code = PinType.TaskPin, Type = typeof(TaskPin)
,IsDefault = true)]
public abstract class Pin : ModelBase
{
private int _pinId;
[Column(IsPrimaryKey = true, IsDbGenerated = true
,DbType = "INT NOT NULL Identity", AutoSync = AutoSync.OnInsert)]
public int PinId
{
get { return _pinId; }
set { SetProperty(ref _pinId, value); }
}
[Column]
internal int _boardId;
private EntityRef<Board> _board;
[Association(Storage = "_board", ThisKey = "_boardId"
,OtherKey = "BoardId", IsForeignKey = true, DeleteOnNull = true)]
public Board Board
{
get { return _board.Entity; }
set
{
if (SetProperty(ref _board, value) != null)
{
_boardId = value.BoardId;
}
}
}
[Column(IsDiscriminator = true)]
public PinType Type { get; set; }
public Pin()
{
}
}
public class TaskPin : Pin
{
private EntitySet<Task> _tasks;
[Association(Storage = "_tasks", OtherKey = "_pinId"
,ThisKey = "PinId", DeleteRule = "CASCADE")]
public EntitySet<Task> Tasks
{
get { return _tasks; }
set { _tasks.Assign(value); }
}
public TaskPin()
{
_tasks = new EntitySet<Task>(new Action<Task>(this.addTask)
,new Action<Task>(this.removeTask));
}
private void addTask(Task task)
{
NotifyPropertyChanging("Task");
task.Pin = this;
}
private void removeTask(Task task)
{
NotifyPropertyChanging("Task");
task.Pin = null;
}
}
[Table]
public class Task : ModelBase
{
private int _taskId;
[Column(IsPrimaryKey = true, IsDbGenerated = true
,DbType = "INT NOT NULL Identity"
,CanBeNull = false, AutoSync = AutoSync.OnInsert)]
public int TaskId
{
get { return _taskId; }
set { SetProperty(ref _taskId, value); }
}
[Column]
internal int _pinId;
private EntityRef<Pin> _pin;
[Association(Storage = "_pin", ThisKey = "_pinId"
,OtherKey = "PinId"
,IsForeignKey = true
,DeleteOnNull=true)]
public Pin Pin
{
get { return _pin.Entity; }
set
{
if (SetProperty(ref _pin, value) != null)
{
_pinId = value.PinId;
}
}
}
public Task()
{
}
}
I create a TaskPin and assign it to a board. Then I create two Tasks and assign them to the TaskPin. This does works fine. The problem occurrs when I try to the one or more Tasks from the TaskPin:
private void OnDeleteTasks(object sender, EventArgs e)
{
TaskPin taskPin = pin as TaskPin;
var completedTasks = taskPin.Tasks
.Where(x => x.IsDone == true)
.ToList();
foreach (var task in completedTasks)
{
taskPin.Tasks.Remove(task);
}
}
If I call then SubmitChanges() on my DataContext object, it will set the Board property of the TaskPin (inherited from Pin) to null.
public void Save(Pin pin)
{
// This is empty so no modified members are identified => Correct
var modifiedMembers = db.Pins.GetModifiedMembers(pin);
// Contains just one entry for the deleted Task entity => Correct
var changeSet = db.GetChangeSet();
// This call will immediately set Board property of Pin to null => Wrong!
db.SubmitChanges();
}
I expect that the Task will be deleted because DeleteOnNull is set to true but I don't know why the Board property of Pin is also set to null which will result in a NullPointerExceptio or that the Pin is also deleted.
I did a google search on this topic but I don't find anything which solved my problem. An Alternative would be to prevent the nulling of the Board property and call DeleteOnSubmit() for Task manually.
To me it appears that the behavior is intended.
If you look at the Pin property in Task class, it is set to be deleted on Null (DeleteOnNull = true) which then the Pin in Task will be deleted as per removeTask() in TaskPin class. Then look at the removePin() method in Board class which sets Board of the Pin to null. Then look at the Board property in Pin class, DeleteOnNull is set to true which will delete the Board from Pin instance when set to null.

Windows phone creating custom objects to columns?

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; }
}

Reflection getting dataContext and Table

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

Formatting LINQ SQL CE data using C# on WP7

I'm very new to C#/LINQ/WP7 development and am struggling to format data being returned from my LINQ query.
I have the following LINQ c# structure:
var boughtItemsInDB = from DBControl.MoneySpent bought in BoughtItemDB.BoughtItems
select bought;
BoughtItems = new ObservableCollection<DBControl.MoneySpent>(boughtItemsInDB);
The definition for MoneySpent is below;
[Table(Name = "MoneySpent")]
public class MoneySpent : INotifyPropertyChanged, INotifyPropertyChanging
{
// Define ID: private field, public property and database column.
private int _itemId;
[Column(IsPrimaryKey = true, IsDbGenerated = true, DbType = "INT NOT NULL Identity", CanBeNull = false, AutoSync = AutoSync.OnInsert)]
public int ItemId
{
get
{
return _itemId;
}
set
{
if (_itemId != value)
{
NotifyPropertyChanging("ItemId");
_itemId = value;
NotifyPropertyChanged("ItemId");
}
}
}
// Define item budget: private field, public property and database column.
private int _itemBudget;
[Column]
public int ItemBudget
{
get
{
return _itemBudget;
}
set
{
if (_itemBudget != value)
{
NotifyPropertyChanging("ItemBudget");
_itemBudget = value;
NotifyPropertyChanged("ItemBudget");
}
}
}
// Define item category: private field, public property and database column.
private string _itemCategory;
[Column]
public string ItemCategory
{
get
{
return _itemCategory;
}
set
{
if (_itemCategory != value)
{
NotifyPropertyChanging("ItemCategory");
_itemCategory = value;
NotifyPropertyChanged("ItemCategory");
}
}
}
// Define item description: private field, public property and database column.
private string _itemDescription;
[Column]
public string ItemDescription
{
get
{
return _itemDescription;
}
set
{
if (_itemDescription != value)
{
NotifyPropertyChanging("ItemDescription");
_itemDescription = value;
NotifyPropertyChanged("ItemDescription");
}
}
}
// Define item amount: private field, public property and database column.
private decimal _itemAmount;
[Column]
public decimal ItemAmount
{
get
{
return _itemAmount;
}
set
{
if (_itemAmount != value)
{
NotifyPropertyChanging("ItemAmount");
_itemAmount = value;
NotifyPropertyChanged("ItemAmount");
}
}
}
// Define item date: private field, public property and database column.
private DateTime _itemDateTime;
[Column]
public DateTime ItemDateTime
{
get
{
return _itemDateTime;
}
set
{
if (_itemDateTime != value)
{
NotifyPropertyChanging("ItemDateTime");
_itemDateTime = value;
NotifyPropertyChanged("ItemDateTime");
}
}
}
I need to format the data returned from the database, the following is stored in my DB:
ItemDateTime - DateTime, ItemDescription - String, ItemAmount - Decimal
I need to be able to to format the Date based on the current locale of the user, and format the decimal to 2 dp.
I am also not sure if I need to use IQueryable when I get the data results .
Any help would be much appreciated.
Thanks,
Mark
Since you don't provide enough detail - just a general idea
var boughtItemsInDB = from bought in BoughtItemDB.BoughtItems
select new { ItemDateTime = bought.ItemDateTime.ToString(), ItemDescription = bought.ItemDescription, ItemAmount = bought.ItemAmount.ToString("0,0.00") };
BUT formatting is better done in the control you use to display the data, not in the Linq query...
EDIT - after the addition frm OP:
From what I see the MoneySpent class is already prepared for "data binding"...
So formatting should be done in the displaying control... for some information see:
What is the WPF XAML Data Binding equivalent of String.Format?
http://www.codeproject.com/KB/WPF/binding_in_linq-sql.aspx
http://odetocode.com/code/740.aspx
http://www.codeguru.com/csharp/.net/wp7/article.php/c18933

How to map with Linq to SQL one to many

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>();

Categories

Resources