I's struggling to get my hands around a database and It seems that every programmer had it's own way of doing it.
I need very simple database that is stored locally and could eventually be moved into a server without much effort. Also I don't want design the database manually as this suppose to only reflect the data used in my program. So I decided to try LINQ with automatic mapping but I have a problem.
This is what I've done:
Create new WPF project.
Add new Service-Based-Database item named myDB.
Write following code:
public partial class MainWindow : Window {
public MainWindow() {
InitializeComponent();
var dc = new DataContext("myDB.mdf");
var dt = dc.GetTable<SimpleData>();
var ds = from d in dt select d;
foreach (var d in ds) {
Debug.WriteLine($"{d.number} : {d.text}");
}
}
}
[Table]
public class SimpleData {
[Column]
public int number { get; set; } = 10;
[Column]
public string text { get; set; } = "hello";
public SimpleData() { }
}
Now at the foreach loop I have an exception:
An attempt to attach an auto-named database for file myDB.mdf failed.
A database with the same name exists, or specified file cannot be
opened, or it is located on UNC share.
What is missing?
Related
I am about to create some library that contains all common functions I used in my projects. (Opening File Dialogs, reading spreadsheets, etc..)
And I am planning to use it when I develop some Form application. All my classes are static in that library project.
Here is a example scenario:
I wrote Library.dll and add it to my Form project as reference. I am always using Console.Writeline() to watch what happened in my code. So I did the same in Library.dll.Lets say I have LibraryClass.cs in my Library.dll And when I call a function from that class to Form project I can not see the Console logs inside of that function.
I create another static class at my library called Report.cs. It creates 2 different type of lists. First one is a string list, and using instead of Console.WriteLine(), I am using this string list. I am using Report.WriteLine() function to add strings inside of that string list. It helps me the collect all the logs that I wrote in Form and also in Library.
The second one is a Record object that I created. It contains information like "Code", "Info", "Title" "Reference", "Type" as properties. Type property allows me to define record as an "Error" or "Warning" or just a "Record". If I can catch an error from catch statement or some warning, I am creating an Record object that contains information I mentioned and I am adding it to that Record list in Report.cs. But I am pretty sure there is a more efficient way to do that.
Here is my Record Object:
public class ReportElement
{
public string Info { get; set; }
public string Title { get; set; }
public DateTime Time;
public string Reference { get; set; }
public string Code { get; set; }
public List<string> Targets { get; set; }
public string Log { get; }
public ReportElementType Type { get; set; }
public ReportElement(string code, string info, string title, ReportElementType reportElementType = ReportElementType.kJournal, string reference = null, List<string> targets = null)
{
this.Info = info;
this.Title = title;
this.Time = DateTime.Now;
this.Code = code;
this.Type = reportElementType;
this.Targets = targets;
this.Reference = reference;
this.Log = this.CreateLogString();
Report.WriteLine(this.Log);
}
public enum ReportElementType
{
kError = 0,
kWarning = 1,
kJournal = 2
}
}
And I am collecting that elements in my Report Class inside of a List:
private static List<ReportElement> RecordedReportElements = new List<ReportElement>();
List of logs(Also in report class:
public static List<string> ListLog = new List<string>();
And I am writing strings in that list with that function:
public static void WriteLine(string Text, bool WithTimer = true)
{
try
{
string logString = WithTimer? Text + " | " + GetTimerValue():Text;
ListLog.Add(logString);
Console.WriteLine(logString);
}
catch (Exception e)
{
Console.WriteLine("Can not be saved in List Log : " + Text);
Console.WriteLine(e.Message);
}
}
At the end I can use this library in any other project like this:
Report.WriteLine("MY LOG STRING")
ReportElement NewElement = new ReportElement(Code, Info, Title, ReportElementType, Reference, Targets);
Report.RecordedReportElements.Add(NewELement)
So the summary of the things I need to achieve:
Creating an journal mechanic ( The list that contains all the record object that i created.)
Collect all console logs from the library I used and form application I am developing.
If some error happens at my library, my library also have to be able to terminate my form application.
After termination I want to be able to make some report visible.(as .txt or .xlsx or as an another form)
So at the end anyone has better strategy to do that or some documentation that explains how to catch errors, and create a report after the process done or terminate.
Thanks.
I'm working on a small WPF app to help me with file organisation. The class I store most of my data in is Project and it contains most of the data the app uses. Therefore, it has a lot of properties which I need to be saved and loaded from a file (around 20, using few as an example)
public DateTime Start { get; set; }
public DateTime End { get; set; }
public Int32 Count { get; set; }
public String Name { get; set; }
public HashSet<String> Files { get; set; }
As far as I know, loading an object can be done in 2 main ways:
I.
Project.cs
public Project Load( String file ) {
Project project = json( file ); //to shorten the question
return project;
}
MainWindow
Project project = new Project();
project = project.Load( file );
II.
Project.cs
public void Load( String file ) {
Project project = json( file );
Start = project.Start;
End = project.End;
Count = project.Count;
Name = project.Name;
Files = project.Files;
}
MainWindow
Project project = new Project();
project.Load( file );
Can I somehow still use void Load() function, but assign the whole object at once?
I tried using this = project;, but it is read-only.
Json .net has a method,
Quick and dirty way to do it using reflection
var project = Json(file); //to shorten the question
foreach (var prop in this.GetType().GetProperties())
{
prop.SetValue(this, prop.GetValue(project));
}
return project;
More performant way using compilation this one is more advanced.
But this looks like somewhat wrong in general when using wpf you should be using some MVVM pattern and the project should be the binding context of your view and you can set the created object from json with out making a copy of the object.
I tried to find a solution for this but couldn't. Here's the problem:
I'm loading data of a bunch of users and creating an object for each user. Each user object has many object properties. Here's the structure:
public class User {
public int ID { get; set; }
public string Name { get; set; }
public City City { get; set; }
public Office Office { get; set; }
}
The City class:
public class City {
public int ID { get; set; }
public string Name { get; set; }
public string Keyword { get; set; }
}
The Office class:
public class Office {
public int ID { get; set; }
public string Address { get; set; }
public int CityID { get; set; }
}
The user object has many other similar properties like City & Office which are basically class objects.
Now here's the main issue. Whenever I try to load all the users into a collection of dictionary, StackOverflow exception occurs at SqlCon.Open() (See the "Fetch" function I've written below). Here's how I'm loading everything:
//Code to load users
Dictionary<int, User> Users = new Dictionary<int, Users>();
DataTable usersData = new DataTable();
//The Fetch function has two version. The first one; which is mentioned in this post, returns the result as Dictionary<string, object>().
//The second version of the function returns the result in the form of the a DataTable and is only used when multiple rows are required from the database. The following returns a set of rows in a DataTable.
Globals.MainDatabase.Fetch("SELECT * FROM users", out usersData);
foreach (DataRow row in usersData.Rows) {
User user = new User();
user.ID = Convert.ToInt32(row["id"]);
user.Name = row["name"].ToString();
user.City = Cities.Get(Convert.ToInt32(row["city_id"]));
user.Office = Offices.Get(Convert.ToInt32(row["office_id"]));
Users.Add(user.ID, user);
}
The methods "Cities.Get(Int32 id)" and "Offices.Get(Int32 id)" uses the following function to fetch data from the database.
public void Fetch(string query, out Dictionary<string, object> results) {
var dict = new Dictionary<string, object>();
try {
using (SqlConnection SqlCon = new SqlConnection(ConnectionString)) {
using (SqlCmd = new SqlCommand()) {
SqlCmd.Connection = SqlCon;
SqlCmd.CommandType = CommandType.Text;
SqlCmd.CommandText = query;
SqlCon.Open();
DataTable temp = new DataTable();
using (SqlDataAdapter SqlAdp = new SqlDataAdapter(SqlCmd)) {
SqlAdp.SelectCommand = SqlCmd;
SqlAdp.Fill(temp);
}
DataRow row = temp.Rows[0];
temp = null;
dict = row.Table.Columns
.Cast<DataColumn>()
.ToDictionary(col => col.ColumnName, col => row.Field<object>(col.ColumnName));
}
}
}
catch (Exception ex) {
HandleException(ex, "An error occurred when tried to fetch data.", query);
}
results = dict;
dict = null;
}
I realize that this "Fetch" function is being called multiple times when creating the user object. The "StackOverflow" exception occurs exactly at this line:
SqlCon.Open();
How can I solve this error? or probably I should use a better approach to do this?
A bit too long for a comment
Do you really need to load ALL data from the database? It is better to just grab the columns and rows you need.
Why are you copying DataTables in to Dictionaries? What is wrong with just using a DataTable?
99.9% of the time you will have better performance performing JOINs in the database.
Don't try to roll your own 'ORM'. Use something like Dapper if you don't want the bloat of EF or NHibernate. Or, stick to ADO (DataTable, DataAdapter etc.)
using (SqlConnection SqlCon = new SqlConnection(ConnectionString)) {
Is your connection string variable really named ConnectionString? Is it possible you are having a name clash with the type? Since it is not declared in the shown code, I assume it is a class variable, so you should respect the conventional naming convention, which would be _connectionString. What does your connection string look like?
Alright folks, I figured it out. It was all because of faulty architecture of the whole demo application. Some objects have one or more other objects as properties and due to some silly faults in the architecture; the "fetch" operation which serves as the base of fetching data from the database, was recursively called resulting into StackOverflow exception which was actually a large number of database connections being initialized ultimately growing the heap size to an extent which causes the exception.
I tried to summarize everything in the paragraph written above because posting the complete source code is useless considering the large amount of code.
Thank you everyone who helped, especially #Guffa's comment on the main post which forced me to investigate the whole issue from scratch rather than sticking to the exception stack.
I am currently making a WPF application and am now ready to add a mongo database, however I can't seem to find the best process to do this with. right now I am doing it like so:
MongoManagment.cs:
namespace MoneyManagment
{
class MongoManagment
{
public void Connect()
{
String connectionString = "mongodb://localhost";
MongoClient client = new MongoClient(connectionString);
MongoServer server = client.GetServer();
MongoDatabase database = server.GetDatabase("MoneyManagment"); //Connect to the database
MongoCollection<Users> _users = database.GetCollection<Users>("user"); // "user" is the collection name, "Users" is the domain class
}
}
public class Users
{
public ObjectId _id { get; set; }
public string username { get; set; }
}
}
then I try to access the data from the domain class in MainWindow.xaml.cs:
namespace MoneyManagment
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
foreach (Users user in _users.FindAll())
{
//do something with users data here
}
}
}
And I get an error here that VS can not access _users, which to an extent makes sense, the problem is though, I have tried a plethora of different ways to make that accessible and it's just not working which leads me to believe that there is a better way to go about this. Any ideas?
First, you need the variable that you want to access to be publicly visible.
public class MongoManagment
{
public MongoCollection<Users> MongoUsers {get; set;}
public void Connect()
{
....
this.MongoUsers = database.GetCollection<Users>("user");
}
then, you need to reference the object in the external class:
public MainWindow()
{
....
MongoManagement mm = new MongoManagement();
mm.Connect();
foreach (Users user in mm.MongoUsers.FindAll())
{
//do something with users data here
}
note this is a very simplistic example, and you may not want a copy of MongoManagment for every window, etc. You will still want to spend a bit of time exploring the concepts of variable lifecycles, scope....
I created a new WCF project in visual studio based on a existing database.
I made two operations. One operation writes a record (createProfile) to the database and one retrieve data (GetProfiles). My project exists of 3 files: web.config, a edmx file and my svc class.
CreateProfile works fine, I checked in SQL and the record is created.
GetProfiles never gives a response. When I debug the context.UserProfileSet always counts 0 values.
Any suggestions on what is going wrong?
[DataContract]
public partial class UserProfile
{
public int Id { get; set; }
[DataMember]
public string UserName { get; set; }
}
public class MusicOwnerService : IMusicOwnerService
{
IEnumerable<UserProfile> GetProfiles()
{
using (MusicOwnerDatabaseEntities context = new MusicOwnerDatabaseEntities())
{
return context.UserProfileSet.AsEnumerable();
}
}
public void CreateProfile()
{
using (MusicOwnerDatabaseEntities context = new MusicOwnerDatabaseEntities())
{
context.UserProfileSet.Add(new UserProfile { UserName = "John" });
context.SaveChanges();
}
}
}
As far as I know, you cant pass an IEnumerable object over the wire with WCF (unless youve a duplex binding of some sort??).. so you would be best to convert to a list and return that list like below:
List<UserProfile> GetProfiles()
{
using (MusicOwnerDatabaseEntities context = new MusicOwnerDatabaseEntities())
{
return context.UserProfileSet.ToList();
}
}