В чем разница между Single и FirstOrDefault?

Возможный дубликат:
LINQ Single vs First

Я новичок в Linq и хочу изучить его наилучшим образом, у меня есть 2 рабочих события обновления для linq, они делают то же самое, но какой способ лучше, и нужно ли мне что-то добавить, чтобы сделать его лучше!?

Решение 1

Protected Sub Button2_Click(sender As Object, e As System.EventArgs) Handles Button2.Click
    Using db As New ThedatabaseconnectionDataContext()
        Try
            Dim TheUpdateID = DirectCast(FindControl("Textbox5"), TextBox).Text
            Dim getEditing As testtable = (From c In db.testtables Where c.test_id = TheUpdateID Select c).FirstOrDefault()
            If getEditing IsNot Nothing Then
                getEditing.test_cat = DirectCast(FindControl("Textbox1"), TextBox).Text
                getEditing.test_info = DirectCast(FindControl("Textbox2"), TextBox).Text
                getEditing.test_number = DirectCast(FindControl("Textbox3"), TextBox).Text
                getEditing.test_datetime = DirectCast(FindControl("Textbox4"), TextBox).Text
                db.SubmitChanges()
                'textBox1.Text = "Contact updated."
            End If
        Catch ex As Exception
            'Me.lblMsg.Text = ex.Message
        End Try
    End Using
End Sub

Решение 2

Protected Sub Button2_Click(sender As Object, e As System.EventArgs) Handles Button2.Click
    Using db As New ThedatabaseconnectionDataContext()
        Try
            Dim tbltest As Table(Of testtable) = db.GetTable(Of testtable)()
            Dim TheUpdateID = DirectCast(FindControl("Textbox5"), TextBox).Text
            Dim getEditing As testtable = tbltest.Single(Function(c) c.test_id = TheUpdateID)
            If getEditing IsNot Nothing Then
                getEditing.test_cat = DirectCast(FindControl("Textbox1"), TextBox).Text
                getEditing.test_info = DirectCast(FindControl("Textbox2"), TextBox).Text
                getEditing.test_number = DirectCast(FindControl("Textbox3"), TextBox).Text
                getEditing.test_datetime = DirectCast(FindControl("Textbox4"), TextBox).Text
                db.SubmitChanges()
                'textBox1.Text = "Contact updated."
            End If
        Catch ex As Exception
            'Me.lblMsg.Text = ex.Message
        End Try
    End Using
End Sub

person Thomas Bøg Petersen    schedule 24.09.2012    source источник
comment
@KirkBroadhurst на самом деле не является дубликатом imo (во всяком случае, связанного вопроса), это вопрос о том, что использовать в каких сценариях, тот, который вы связали, спрашивает, что более эффективно для одной записи   -  person Manatherin    schedule 24.09.2012


Ответы (2)


С чего бы вообще начать с этого...

Для начала я знаю, что это, скорее всего, тестовый проект, поэтому извините, если вы уже занимаетесь этим, но, пожалуйста, убедитесь, что вы используете приемлемые иерархии уровней данных — ваш DBML должен находиться в отдельном проекте от вашего уровня представления.

Но, к вопросу в руке. Мой предпочтительный способ сделать это — получить объект данных и обновить его на уровне объекта. Например, (псевдокод/я парень на С#!):

private MyObject object;

protected void Page_Load(object sender, EventArgs e)
{
    // Select usually be ID
    object = DataLayer.GetObject();

    if(!IsPostBack)
    {
         // Load object details for editing into presentation layer
         TextboxObjectName.Text = object.Name;
    }
}

protected void Button_Click(object sender, EventArgs e)
{
     // Button click event - update object and send it to database
     object.Name = TextboxObjectName.Text;

     DataLayer.UpdateObject(object);
}

Это использует отслеживание объектов, и тогда слой Daya может выглядеть так:

function void UpdateObject(MyObject obj)
{
    using (TestDataContext db = new TestDataContext ())
    {

       db.MyObjects.Attach(obj);

       db.Refresh(RefreshMode.KeepCurrentValues, obj);

       db.SubmitChanges();
    }
}
person Chris Dixon    schedule 24.09.2012
comment
Находится ли MyObject на той же странице или в файле класса!? Где вы указываете, какой идентификатор обновлять !? - person Thomas Bøg Petersen; 24.09.2012
comment
MyObject — это автоматически сгенерированный класс, который сгенерирует ваша DBML. Скажем, если ваша таблица была названа Files, то у вас будет автоматически сгенерированный класс File, в котором будет отслеживаться Entity Framework. Идентификатор для выбора объекта можно увидеть в комментарии Page_Load. - person Chris Dixon; 24.09.2012

Во-первых, вы должны иметь возможность написать свой первый или по умолчанию как

Dim getEditing As testtable = tbltest.FirstOrDefault(Function(c) c.test_id = TheUpdateID)

Непроверено, но больше, чтобы указать, что first или default обрабатывает лямбда-выражения

Что касается того, что использовать, это зависит от ваших данных. Чтобы сломать то, что происходит

Одиночный - Ожидается ровно одно совпадение. Исключение выдается, если результаты не найдены ИЛИ найдено несколько результатов.

SingleOrDefault — ожидает 0 или 1 совпадение. Исключение выдается, если найдено несколько совпадений

Первый — ожидает 1 или несколько совпадений. Исключение выдается, если совпадений не найдено. Любые результаты после первого игнорируются.

FirstOrDefault — обрабатывает 0, 1 или несколько совпадений. Любые результаты после первого игнорируются.

Если вы выбираете на основе идентификатора из списка (т.е. он уникален и определенно находится в базе данных), то одиночный вариант является безопасным выбором.

Если пользователь вводит идентификатор (опять же уникальный), который может быть или не быть в БД одиночным или по умолчанию безопасным.

Если поиск основан на возможном повторяющемся значении, таком как фамилия, то first или firstordefault — это то, что вы должны использовать в зависимости от того, гарантированно ли оно существует в базе данных или нет.

Лично я, независимо от данных, придерживаюсь либо first, либо first, либо default, так как он обрабатывает больше сценариев.

person Manatherin    schedule 24.09.2012
comment
Возможно, добавление: «FirstOrDefault — обрабатывает 0, 1 или несколько совпадений» — но игнорирует все после первого совпадения - person Hans Kesting; 24.09.2012
comment
@HansKesting Хороший вопрос, изменил мой ответ - person Manatherin; 24.09.2012
comment
Отличный ответ......Просто добавьте, если у меня есть это, что вы рекомендуете........Dim tbltest As Table(Of testtable) = db.GetTable(Of testtable)() Dim TheUpdateID = DirectCast( FindControl(Textbox5), TextBox).Text Dim getEditing As testtable = tbltest.FirstOrDefault(Function(c) c.test_id = TheUpdateID) Как использовать INNER, если моя таблица имеет имена testtable и maintable, и я хочу получить информацию из maintable , где main_id = test_id !? - person Thomas Bøg Petersen; 24.09.2012
comment
@ThomasBøgPetersen Я не уверен, что понимаю, что ты имеешь в виду - person Manatherin; 24.09.2012
comment
Hej Manatherin, я имею в виду, как мне сделать (в данном случае) Dim tdltest, если у меня есть этот старый SQL-запрос, который получает информацию из 2 таблиц..... Dim cmd As New SqlCommand (SELECT Groups.Name FROM Roles INNER JOIN Groups ON Roles.GroupID = Groups.GroupID INNER JOIN Users ON Roles.UserID = Users.UserID AND Users.Username=@UserName, conn) - person Thomas Bøg Petersen; 24.09.2012
comment
@ThomasBøgPetersen, в общем, я бы сказал, что вы должны запросить пользователя и пройти через отношения, например, получить пользователя, вызвать .Groups, тогда вы можете сделать select many, чтобы получить имена групп, такие как .Groups.SelectMany(x =› x.Roles.select(y => y.Name)), Ничто из этого не тестировалось и, вероятно, не будет компилироваться, а просто для того, чтобы дать вам представление. В качестве альтернативы вы можете вызвать хранимую процедуру или выполнить SQL из структуры сущностей. Вы можете присоединиться к LINQ, но я стараюсь не использовать эту функцию, поэтому кто-то другой может помочь вам больше, если вы зададите ее как отдельный вопрос. - person Manatherin; 25.09.2012