kotlin 为什么空值在我的房间实体中变为0?

tct7dpnv  于 2023-10-23  发布在  Kotlin
关注(0)|答案(3)|浏览(147)

在我的SQLite数据库中,我定义了这个表:

CREATE TABLE `lh_psalm_join` (
    `groupFK` INTEGER  NOT NULL,
    `readingFK` INTEGER  NOT NULL,
    `theOrder` INTEGER NOT NULL,
    `themeFK` INTEGER DEFAULT NULL,
    `epigraphFK` INTEGER DEFAULT NULL,
    `thePart` INTEGER DEFAULT NULL,
    PRIMARY KEY (`groupFK`, `readingFK`),
    FOREIGN KEY(`groupFK`) REFERENCES `lh_psalmody_join`(`groupID`) ON DELETE CASCADE ON UPDATE CASCADE,
    FOREIGN KEY(`readingFK`) REFERENCES `lh_psalm`(`psalmID`) ON DELETE CASCADE ON UPDATE CASCADE,
    FOREIGN KEY(`epigraphFK`) REFERENCES `lh_epigraph`(`epigraphID`) ON DELETE SET NULL ON UPDATE CASCADE,
    FOREIGN KEY(`themeFK`) REFERENCES `lh_theme`(`themeID`) ON DELETE SET NULL ON UPDATE CASCADE
  );

我的问题是关于theOrder列,在实体中我这样定义它:

@ColumnInfo(name = "thePart", defaultValue = "NULL")
var thePart: Int?

检索数据,当数据库中theParte的值为null时,它就变成了0
我意识到这一点,因为当我试图做这个检查时,它告诉我它总是正确的:

if (thePart != null || thePart !=0)

在房间中,null值是否转换为0if (myVaule != 0)对这种情况是否足够?
我看了documentation,找不到任何关于它的东西。

2cmtqfgy

2cmtqfgy1#

房间未将null转换为0。你对自己条件句的分析

thePart != null || thePart != 0

不正确.
考虑thePart值的三种可能类别:
| thePart的值|结果|
| --|--|
| null| thePart != 0为true|
| 0 |thePart != null为true|
| 除0以外的任何整数|thePart != null为true|
所以无论如何,两个条件中的一个都为真,并且两个条件都使用||,所以它必须始终为真。

izkcnapc

izkcnapc2#

简而言之,Room不会将null转换为0,根据警告问题,您的逻辑将始终导致true。

    • 事实上,如果在使用Kotlin时有任何相反的情况,如果一个整数类型是不可空的,并且是主键(唯一),那么如果值为0,Room将有效地将该值视为null,并且不会在插入中提供值,以便生成值 *
      说明

我意识到这一点,因为当我试图做这个检查时,它告诉我它总是正确的:if (thePart != null || thePart !=0)
假设thePart为null
如果是零的话,那就是零,如果是零的话,那就是零,如果是零,那就是零。
如果thePart是10(或者除了0以外的任何值),那么因为10不是null,所以你得到一个true。
在零件为0的情况下,0也不是null,所以为真。
因此,你总是会得到真实的,与房间无关。

介绍房间的功能

忽略Foreign Keys(因为它们需要引用的表存在),那么您的@Entity类将沿着行:-

@Entity(tableName = "lh_psalm_join", primaryKeys = ["groupFK","readingFK"])
data class LH_PSALM(
    var groupFK: Int,
    var readingFK: Int,
    var theOrder: Int,
    @ColumnInfo(defaultValue = "NULL")
    var themeFK: Int?=null,
    @ColumnInfo(defaultValue = "NULL")
    var epigraph: Int?=null,
    @ColumnInfo(defaultValue = "NULL")
    var thePart: Int?=null
    /* Foreign keys omitted */
)

也是一个@Dao注解接口,允许插入和提取数据

@Dao
interface TheDAOS{
    @Insert(onConflict = OnConflictStrategy.IGNORE)
    fun insert(lhPsalm: LH_PSALM): Long
    @Query("SELECT * FROM lh_psalm_join")
    fun getAllLHPSALMs(): List<LH_PSALM>
}
  • 即根本没有特殊处理。

这将生成create SQL:

CREATE TABLE IF NOT EXISTS `lh_psalm_join` (
    `groupFK` INTEGER NOT NULL, 
    `readingFK` INTEGER NOT NULL, 
    `theOrder` INTEGER NOT NULL, 
    `themeFK` INTEGER DEFAULT NULL, 
    `epigraph` INTEGER DEFAULT NULL, 
    `thePart` INTEGER DEFAULT NULL, 
    PRIMARY KEY(`groupFK`, `readingFK`)
)

也就是说,将外键与问题中提供的SQL相同。

  • 可空字段的外键很可能会导致问题和焦虑,但这超出了问题的范围。他们的加入将使问题变得模糊。

现在考虑下面的活动代码(注意,为了简洁和方便,.allowMainThreadQueries方法已经包含在Room databaseBuilder中):

class MainActivity : AppCompatActivity() {
    lateinit var db: TaskRoomDatabase
    lateinit var dao: TheDAOS
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        db = TaskRoomDatabase.getDatabase(this)
        dao = db.getTheDAOs()

        var lp = LH_PSALM( groupFK = 1, readingFK = 1, 99, null, null, null)
        dao.insert(lp)
        dao.insert(LH_PSALM(2,2,98,1,null,null))
        dao.insert(LH_PSALM(3,3,97))
        dao.insert(LH_PSALM(4,4,96,0,0,0))

        for(lp in dao.getAllLHPSALMs()) {
            Log.d("DBINFO","GFK=${lp.groupFK} RFK=${lp.readingFK} ORD=${lp.theOrder} THM=${lp.themeFK} EP=${lp.epigraph} PRT=${lp.thePart}" +
                    " The logical processing of the thePart field:-" +
                    "\n\t Is thePart NOT EQUAL TO NULL?: ${lp.thePart!=null}" +
                    " Is thePart NOT EQUAL to 0?: ${lp.thePart!=0}" +
                    " Is thePart NOW EQUAL TO NULL OR NOT EQUAL TO 0 ${(lp.thePart!=null || lp.thePart!=0)}"
            )
        }
    }
}

第一次运行(上述仅打算运行一次)的日志结果包括:-

D/DBINFO: GFK=1 RFK=1 ORD=99 THM=null EP=null PRT=null The logical processing of the thePart field:-
         Is thePart NOT EQUAL TO NULL?: false Is thePart NOT EQUAL to 0?: true Is thePart NOW EQUAL TO NULL OR NOT EQUAL TO 0 true
D/DBINFO: GFK=2 RFK=2 ORD=98 THM=1 EP=null PRT=null The logical processing of the thePart field:-
         Is thePart NOT EQUAL TO NULL?: false Is thePart NOT EQUAL to 0?: true Is thePart NOW EQUAL TO NULL OR NOT EQUAL TO 0 true
D/DBINFO: GFK=3 RFK=3 ORD=97 THM=null EP=null PRT=null The logical processing of the thePart field:-
         Is thePart NOT EQUAL TO NULL?: false Is thePart NOT EQUAL to 0?: true Is thePart NOW EQUAL TO NULL OR NOT EQUAL TO 0 true
D/DBINFO: GFK=4 RFK=4 ORD=96 THM=0 EP=0 PRT=0 The logical processing of the thePart field:-
         Is thePart NOT EQUAL TO NULL?: true Is thePart NOT EQUAL to 0?: false Is thePart NOW EQUAL TO NULL OR NOT EQUAL TO 0 true

1.显然,Room没有将null替换为0,反之亦然。THM=null EP=null PRT=null
1.逻辑结果清楚地表明,即使部分为假,对两个测试进行OR运算,也会返回假。
为了进一步证明空值存储在数据库中,应用程序检查(在运行上述程序后)显示:

nnvyjq4y

nnvyjq4y3#

默认值:在Room实体类中定义属性时,如果未指定默认值,则该属性将被设置为其数据类型的默认值。例如,如果您有一个整数字段,并且它没有显式设置为值,则它将默认为0。

@Entity
public class MyEntity {
    @PrimaryKey
    public int id;

    public int myIntegerField; // Defaults to 0 if not explicitly set
}

对于空值

@Entity
public class MyEntity {
    @PrimaryKey
    public int id;

    @Nullable
    public Integer myNullableIntegerField; // Allows null values
}

相关问题