Linq doesn't insert associated entity on insert - c#

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

Related

LINQ query does not return child fields

I think I'm getting stupid because I can't get my LINQ query to work as I expect. I have one class that has 3 relationships to other classes.
This is the main class
[Table(Name = "scanResult")]
public class SniffResult
{
public SniffResult()
{
}
public SniffResult(Address address)
{
this.address = address;
}
private int _pk_SniffResult;
[Column(IsPrimaryKey = true, IsDbGenerated = true, Storage = "_pk_SniffResult", Name ="pk_scanResult")]
public int pk_SniffResult { get { return _pk_SniffResult; } set { this._pk_SniffResult = value; } }
private int _fk_scan;
[Column(Storage = "_fk_scan", Name = "scan")]
public int fk_scan { get { return _fk_scan; } set { this._fk_scan = value; } }
private Scan _scan;
[Association(Storage = "_scan", IsForeignKey = true, ThisKey = "fk_scan", OtherKey = "pk_scan")]
public Scan scan { get { return _scan; } set { this._scan = value; } }
private int _fk_address;
[Column(Storage = "_fk_address", Name = "address")]
public int fk_adress { get { return _fk_address; } set { this._fk_address = value; } }
private Address _address;
[Association(Storage ="_address", IsForeignKey = true, ThisKey = "fk_adress", OtherKey = "pk_address")]
public Address address { get { return _address; } set { this._address = value; } }
private string _rawResult;
[Column(Storage = "_rawResult", Name = "raw")]
public string rawResult { get { return _rawResult; } set { this._rawResult = value; } }
private int _code = -5;
[Column(Storage = "_code")]
public int code { get { return _code; } set { this._code = value; } }
private DateTime _scanDate = DateTime.Now;
[Column(Storage = "_scanDate")]
public DateTime scanDate { get { return _scanDate; } set { this._scanDate = value; } }
private int? _fk_proxy;
[Column(Storage = "_fk_proxy", Name = "usedProxy", CanBeNull = true)]
public int? fk_proxy { get { return _fk_proxy; } set { this._fk_proxy = value; } }
private ProxyData _usedProxy;
[Association(Storage = "_usedProxy", IsForeignKey = true, ThisKey = "fk_proxy", OtherKey = "pk_proxy")]
public ProxyData usedProxy { get { return _usedProxy; } set { this._usedProxy = value; } }
public string message { get; set; } = "";
public bool availability { get; set; }
public int planCode { get; set; }
public string planning { get; set; }
public override string ToString()
{
return string.Format("availability={0}, code={1}, message={2}", availability, code, message);
}
}
This is one of the child classes
[Table(Name = "address")]
public class Address
{
private int _pk_address;
[Column(IsPrimaryKey = true, IsDbGenerated = true, Storage = "_pk_address")]
public int pk_address { get { return _pk_address; } set { this._pk_address = value; } }
private string _provId;
[Column(Storage = "_provId")]
public string provId { get { return _provId; } set { this._provId = value; } }
private string _zipcode;
[Column(Storage = "_zipcode")]
public string zipcode { get { return _zipcode; } set { this._zipcode = value; } }
private int _houseNumber;
[Column(Storage = "_houseNumber")]
public int houseNumber { get { return _houseNumber; } set { this._houseNumber = value; } }
private string _addressAddition;
[Column(Storage = "_addressAddition")]
public string addressAddition { get { return _addressAddition; } set { this._addressAddition = value; } }
public string ToAddresString()
{
return string.Format("{0} {1}{2}", this.provId, zipcode, houseNumber, addressAddition);
}
public override string ToString()
{
return string.Format("{0}:\t{1}\t{2}{3}", this.provId, zipcode, houseNumber, addressAddition);
}
}
I want to get SniffResult including the associated fields. But they are all null. This is the code I use:
SniffDAO dao = new SniffDAO();
var test = from sr in dao.SniffResults
where sr.fk_scan == 3
select sr;
foreach (var one in test)
{
Console.WriteLine(one.pk_SniffResult);
Console.WriteLine(one.address);
}
one.address gives me a null, what am I doing wrong?
This is the Dao class
public class SniffDAO
{
private string currentDir;
private DataContext db;
public Table<Scan> Scans { get; set; }
public Table<SniffResult> SniffResults { get; set; }
public Table<Address> Addresses { get; set; }
public SniffDAO()
{
db = new DataContext(#"Data Source=(LocalDB)\MSSQLLocalDB;AttachDbFilename=********;Integrated Security=True;Asynchronous Processing=True");
db.ObjectTrackingEnabled = true;
Scans = db.GetTable<Scan>();
SniffResults = db.GetTable<SniffResult>();
Addresses = db.GetTable<Address>();
currentDir = Directory.GetCurrentDirectory();
}
public void save()
{
db.SubmitChanges();
}
}
You need to Include related entities like this:
SniffDAO dao = new SniffDAO();
var test = dao.SniffResults.Include(x=>x.address).Where(sr.fk_scan == 3);
foreach (var one in test)
{
Console.WriteLine(one.pk_SniffResult);
Console.WriteLine(one.address);
}
I found the solution thanks to #Kris. I now use:
DataLoadOptions dlo = new DataLoadOptions();
dlo.LoadWith<SniffResult>(sr => sr.address);
dlo.LoadWith<SniffResult>(sr => sr.usedProxy);
dlo.LoadWith<SniffResult>(sr => sr.scan);
db.LoadOptions = dlo; //db is the DataContext
See https://msdn.microsoft.com/en-us/library/bb548760(v=vs.110).aspx for more info

Filtering mongodb data

I have the following model:
Base class:
public abstract class Identifiable{
private ObjectId id;
private string name;
protected Identifiable(){
id = ObjectId.GenerateNewId();
}
[BsonId]
public ObjectId Id{
get { return id; }
set { id = value; }
}
[BsonRequired]
public string Name{
get { return name; }
set { name = value; }
}
}
The name is unique.
A channel class
public class Channel : Identifiable{
private DateTime creationDate;
private string url;
private DailyPrograming dailyPrograming;
public DailyPrograming DailyPrograming{
get { return dailyPrograming; }
set { dailyPrograming = value; }
}
public DateTime CreationDate{
get { return creationDate; }
set { creationDate = value; }
}
public string Url{
get { return url; }
set { url = value; }
}
}
Daily programs. The name property is the date stored as ddMMyyyy:
public class DailyPrograming : Identifiable{
public DailyPrograming(){
DailyPrograms = new List<Program>(30);
}
public IList<Program> DailyPrograms { get; set; }
}
The programs:
public class Program : Identifiable{
private DateTime programDate;
private string category;
private string description;
public DateTime ProgramDate{
get { return programDate; }
set { programDate = value; }
}
public string Category{
get { return category; }
set { category = value; }
}
public string Description{
get { return description; }
set { description = value; }
}
}
Now, I want to filter the program of certain channel for specific date using:
public DailyPrograming GetProgramsForDate(string channelId, string prgDate){
ObjectId id = new ObjectId(channelId);
IMongoQuery query = Query.And(Query<Channel>.EQ(c => c.Id, id),
Query<DailyPrograming>.EQ(dp => dp.Name, prgDate));
var result = Database.GetCollection<DailyPrograming>(CollectionName).Find(query).FirstOrDefault();
return result;
}
But it never returns the existing data. How to retrieve the programings of a channel for a date?
-
var builder = Builders<BsonDocument>.Filter;
var filt = builder.Eq("Price", "9.20")
& builder.Eq("ProductName", "WH-208");
var list = await collection.Find(filt).ToListAsync();
We can use & instead of $and. See this post, for another example.
According to your sample I used id = "54c00c65c215161c7ce2a77c" and prgDate = "2212015"
then I changed the query to this:
var collection = database.GetCollection<Channel>("test6");
var id = new ObjectId("54c00c65c215161c7ce2a77c");
var query = Query.And(Query<Channel>.EQ(c => c.Id, id), Query<Channel>.EQ(c => c.DailyPrograming.Name, "2212015"));
var result = collection.Find(query).FirstOrDefault();
this query works fine
Some point:
Your collection type is Chanel not DailyPrograming
When your collection is Chanel you have to use Query<Channel> and query nested DailyPrograming via Query<Channel>.EQ(c => c.DailyPrograming.Name, "2212015")

Find an ID through having a username?

SOLVED
THANKS TO HAR07 FOR HELPING ME OUT AND ANYONE THAT ELSE HAS COMMENTED!
public partial class xamlAuditorDashboard : Window
{
cEvolve_SP sp = new cEvolve_SP(Properties.Settings.Default.AppConnectionString);
List<cAuditTasksEntity> _tasks;
cAuditUserEntity _loggedInUser;
public xamlAuditorDashboard(cAuditUserEntity loggedInUser)
{
_loggedInUser = loggedInUser;
InitializeComponent();
_tasks = new List<cAuditTasksEntity>();
Refresh();
}
private void Refresh()
{
var _AuditUserId = _loggedInUser;
cAuditUserEntity user = _AuditUserId as cAuditUserEntity;
int userid = user.AuditUserId;
_tasks = sp.GetTasksByUser(userid).ToList();
var result = (from cAuditTasksEntity tasks in _tasks
select tasks.TaskId).ToList();
cmbToDoList.ItemsSource = result;
}
private void btnAudit_Click(object sender, RoutedEventArgs e)
{
var Audit = cmbToDoList.SelectedItem;
var _TransactionId = Audit;
cAuditTransactionsEntity transaction = _TransactionId as cAuditTransactionsEntity;
string transactionid = transaction.TransactionId;
sp.GetTransactionInfo(transactionid);
}
What I am trying to do is, from having a TaskId I want to find out the TransactionId.
From my code in my Refresh method I getting the LoggedOnUser and searching the TaskTable for it then to bring out any tasks that there ID is next to, then to display the `TaskIds' in a combobox on there page.
What i am looking to do is when they click on the TaskId in the combobox and click New Audit, another page will load up and display all different information.
http://i.stack.imgur.com/Bgek2.png
This is the TaskTable, the TaskID is what shows up in there combobox.
When they select a new ID from there combobox and click next, I need it to find the transactionId next to the TaskId they clicked, then bring back:
http://i.stack.imgur.com/APp6E.png
all the information in the circle?
EDIT:
The cAuditTasksEntity:
namespace DAL
{
[Table(Name = "Audit_Tasks")]
public class cAuditTasksEntity
{
private int _TaskId;
private int _AuditUserId;
private string _TransactionId;
private string _TaskTypeId;
private DateTime _Date;
private string _AuditStatus;
[Column(DbType = "INT", IsPrimaryKey = true, IsDbGenerated = true)]
public int TaskId
{
get { return _TaskId; }
set { _TaskId = value; }
}
[Column(DbType = "INT")]
public int AuditUserId
{
get { return _AuditUserId; }
set { _AuditUserId = value; }
}
[Column(DbType = "CHAR(32)")]
public string TransactionId
{
get { return _TransactionId; }
set { _TransactionId = value; }
}
[Column(DbType = "CHAR(32)")]
public string TaskTypeId
{
get { return _TaskTypeId; }
set { _TaskTypeId = value; }
}
[Column(DbType = "DATETIME")]
public DateTime Date
{
get { return _Date; }
set { _Date = value; }
}
[Column(DbType = "VARCHAR(255)")]
public string AuditStatus
{
get { return _AuditStatus; }
set { _AuditStatus = value; }
}
}
}
Also the properties i see are these 4 :
ToString();
GetHashCode();
GetType();
Equals();
EDIT2:
This is what Audit.GetType(); is showing but I don't understand?
I added this code:
var result = Audit.GetType();
and then this set result to be equal to:
{Name = "Int32" FullName = "System.Int32"
I think this is what you are looking for, getting transactionId given TaskId:
var _TransactionId = (from task transactionid in _tasks
where task.TaskId == (int)cmbToDoList.SelectedItem
select task.TransactionId).FirstOrDefault();

Getting StackOverflowException when setting property

public List<Empleado> ListarEmpleados()
{
List<Empleado> returnList = new List<Empleado>();
var lista = from u in DB.tabEmpleado
select new
{
u.idEmpleado,
u.idUsuario,
u.Nombre,
u.Apellidos,
u.Telefono1
};
foreach (var e in lista)
{
Empleado empleado = new Empleado();
empleado.idEmpleado = e.idEmpleado;
empleado.idUsuario = e.idUsuario;
empleado.nombre = e.Nombre;
empleado.apellidos = e.Apellidos;
empleado.telefono1 = e.Telefono1;
returnList.Add(empleado);
}
return returnList;
}
This is a WCF service, when is called it returns StackOverflow error in the class definition, exactly in the Set property of idEmpleado.
Class definition is here.
[DataContract]
public class Empleado
{
private int _idEmpleado;
[DataMember(IsRequired = false)]
public int idEmpleado
{
get { return _idEmpleado; }
set { idEmpleado = value; } ERROR
}
private int _idUsuario;
[DataMember(IsRequired = false)]
public int idUsuario
{
get { return _idUsuario; }
set { idUsuario = value; }
}
private string _nombre;
[DataMember(IsRequired = false)]
public string nombre
{
get { return _nombre; }
set { nombre = value; }
}
private string _apellidos;
[DataMember(IsRequired = false)]
public string apellidos
{
get { return _apellidos; }
set { apellidos = value; }
}
private string _telefono1;
[DataMember(IsRequired = false)]
public string telefono1
{
get { return _telefono1; }
set { telefono1 = value; }
}
}
}
Does anybody know where the error is?
Thanks in advance.
You are setting the value of the property by calling the property setter again, instead of directly setting its backing field. This causes an infinite recursion and a stack overflow as a result.
public int idEmpleado
{
get { return _idEmpleado; }
set { idEmpleado = value; } // SHOULD BE _idEmpleado = value
}

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