Podwójny warunek sprawdzający czy istnieje rekord w bazie

0

Przed dodaniem nowego rekordu do bazy danych chce sprawdzić czy istnieje już taki rekord w bazie. A mianowicie czy użytkownik odpowiedział już na aktualne pytanie. Jednak coś robię źle i wyskakuje mi taki błąd

 
Wystąpił nieobsługiwany wyjątek typu „System.NotSupportedException” w EntityFramework.SqlServer.dll

Dodatkowe informacje: Unable to create a constant value of type 'Program_Do_Głosowania.Models.Question'. Only primitive types or enumeration types are supported in this context.

Warunek wygląda tak:

 
if (temp = dbcontext.Answers.Where(q => q.SomeQuestion == question && q.SomeUser == user).FirstOrDefault()) == null)

Model bazy:

public int AnswerID { get; set; }
        public eOptionToVote Voted{ get; set; }
        public virtual User SomeUser { get; set; }
        public virtual Question SomeQuestion { get; set; }
 
5

A jak Twoim zdaniem ten kod: q.SomeQuestion == question powinien wyglądać po przekształceniu do SQL?

Kod operujący na obiektach w C# jest przez Entity Framework przekształcany na kod operujący na wierszach tabel bazy danych. EF nie wie wg jakich kryteriów chcesz porównywać wartości tych wierszy, czy chodzi Ci o samą wartość klucza głównego, a może o wartości wszystkich kolumn na raz, czy jeszcze coś innego. Musisz to dokładniej sprecyzować, i porównywać ze sobą wyłącznie wartości proste (liczby, stringi, boole), nie własne obiekty.

1

Czyli mogłoby to wyglądać np. tak:

 
bool answerExist = dbcontext.Answers.Any(q => q.SomeQuestion.QuestionId == question.QuestionId && q.SomeUser.UserId == user.UserId )

Zakładając oczywiście, że encje User i Question mają klucze główne UserId i QuestionId. Dlaczego Any()? O ile się nie mylę nie ma w tym przypadku konieczności pobierania z bazy całego obiektu Answer jeżeli chcemy tylko sprawdzić czy istnieje.

1
RoyalBandit napisał(a):

Dlaczego Any()? O ile się nie mylę nie ma w tym przypadku konieczności pobierania z bazy całego obiektu Answer jeżeli chcemy tylko sprawdzić czy istnieje.

Owszem, nie ma takiej konieczności. Ale znając EF, nie zdziwiłbym się, gdyby pobrał te rekordy. Sprawdź SQL Profilerem, czy tak się nie dzieje.

0

Poradzie mi czemu wyświetla mi taki błąd:
Exception thrown: 'System.Data.Entity.Core.EntityCommandExecutionException' in EntityFramework.SqlServer.dll ("An error occurred while executing the command definition. See the inner exception for details.")

przy wywołaniu polecenia

 var answercollection = dbcontext.Answers.Where(x => x.SomeQuestion.questionID == questo.questionID).Select(x => new { x.optionToVote }).ToList();
 

Model wygląda tak:
Klasa Answer

 
    public class Answer : INotifyPropertyChanged
    {
        private int AnswerID;
        public int answerID
        {
            get { return AnswerID; }
            set
            {
                if (AnswerID != value)
                {
                    AnswerID = value;
                    OnPropertyChange("answerID");
                }
            }
        }
        private eOptionToVote OptionToVote;
        public eOptionToVote optionToVote
        {
            get { return OptionToVote; }
            set
            {
                if (OptionToVote != value)
                {
                    OptionToVote = value;
                    OnPropertyChange("optionToVote");
                }
            }
        }
        public virtual User SomeUser { get; set; }
        public virtual Question SomeQuestion { get; set; }

        public event PropertyChangedEventHandler PropertyChanged;

        public void OnPropertyChange(string property)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(property));
            }
        }
    }

Klasa Question

  public class Question : INotifyPropertyChanged
    {
        private int QuestionID;
        public int questionID
        {
            get { return QuestionID; }
            set
            {
                if (QuestionID != value)
                {
                    QuestionID = value;
                    OnPropertyChange("questionID");
                }
            }
        }
        private string Title;
        public string title
        {
            get { return Title; }
            set
            {
                Title = value;
                OnPropertyChange("title");
            }
        }
        public virtual ICollection<Answer> AnswerCollection { get; set; }
        public event PropertyChangedEventHandler PropertyChanged;
        public void OnPropertyChange(string propertyName)
        {
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }

klasa user

     public class User : INotifyPropertyChanged
    {
        private int UserID;
        public int userID
        {
            get { return UserID; }
            set
            {
                if (UserID != value)
                {
                    UserID = value;
                    OnPropertyChange("userID");
                }
            }
        }
        private string Login;
        public string login
        {
            get { return Login; }
            set
            {
                if (Login != value)
                {
                    Login = value;
                    OnPropertyChange("login");
                }
            }
        }
        private eOptionToVote OptionTypeLogin;
        public eOptionToVote optionTypeLogin
        {
            get { return OptionTypeLogin; }
            set
            {
                if (OptionTypeLogin != value)
                {
                    OptionTypeLogin = value;
                    OnPropertyChange("optionTypeLogin");
                }
            }
        }
        public virtual ICollection<Answer> AnswerCollection { get; set; }

        public event PropertyChangedEventHandler PropertyChanged;

        public void OnPropertyChange(string property)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(property));
            }
        }
    }
0
Marcino24 napisał(a):

Exception thrown: 'System.Data.Entity.Core.EntityCommandExecutionException' in EntityFramework.SqlServer.dll ("An error occurred while executing the command definition. **See the inner exception for details.**")

A co masz w inner exception?

Poza tym nie powinieneś używać obiektów do komunikacji pomiędzy View a ViewModel w EF, to kompletnie nie ta warstwa.

0

Porada poboczna.
Zamiast w każdej klasie implementować INotifyPropertyChanged, utwórz klase BindableBase lub Notificationobject. Następnie wszystkie trzy klasy User,Question, Answer powinny dziedziczyć po tej klasie.

  1. Przy okazji znikną wszystkie magiczne ciągi znaków jak: "optionTypeLogin" w których łatwo popełnić literówke.
  2. Dodatkowo twój kod zmniejszy się o połowe.
  3. Większa czytelność
  4. Chyba że idziesz na ilość zamiast jakości :)
    Są już do tego gotowe klasy:
    https://github.com/PrismLibrary/Prism/blob/master/Source/Prism/Mvvm/BindableBase.cs
0

Nie wiem czy o to ci chodziło ale znalazłem coś takiego:
dbcontext.Answers.Where(x => x.SomeUser.userID == usre.userID).Select = [Expression is not supported while IntelliTrace debugging]

Możesz rozwinąć swoja myśli bo nie do końca rozumie
<quote="1287416">

Marcino24 napisał(a):
Poza tym nie powinieneś używać obiektów do komunikacji pomiędzy View a ViewModel w EF, to kompletnie nie ta warstwa.
1

Nie o to. :) Zrób coś takiego:

try
{
    // Twój kod.
}
catch (Exception ex)
{
    Debug.WriteLine(ex.ToString());
}

Uruchom program w debugu i pokaż to co się pojawiło w okienku Outpu jak nie masz go na wierzchu to kliknij w Visual Studio View -> Output (skrót klawiszowy to CTRL + W O).

Możesz rozwinąć swoja myśli bo nie do końca rozumie

Chodzi mi to że jak piszesz aplikację w WPF to powinieneś stosować się do wzorca warstwy prezentacji MVVM więcej na ten temat tutaj:
https://msdn.microsoft.com/en-us/library/hh848246.aspx
https://msdn.microsoft.com/pl-pl/library/wprowadzenie-do-wzorca-projektowego-model-view-viewmodel-na-przykladzie-aplikacji-wpf.aspx

Ogólnie chodzi mi o to że jeden obiekt nie powinien być odpowiedzialny za przekazywanie danych do widoku jak również za mapowienie tabel z bazy danych, powinno to być od siebie odseparowane.

0 użytkowników online, w tym zalogowanych: 0, gości: 0